URL.createObjectURL(mediaSource) - play back video from URL - MOOV atom - Elastic Transcoder - amazon-s3

I am trying to play back a video (currently hosted on S3 with public access) by creating a blob URL.
I have used Elastic Transcoder to encode the video since it is supposed to set the MOOV atom to the top (beginning).
I am unable to get the code to work but also found a working example: link here
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<video controls></video>
<script>
var video = document.querySelector('video');
var assetURL = 'https://ovation-blob-url-test.s3.amazonaws.com/AdobeStock_116640093_Video_WM_NEW.mp4';
// Need to be specific for Blink regarding codecs
// ./mp4info frag_bunny.mp4 | grep Codec
var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource;
//console.log(mediaSource.readyState); // closed
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
function sourceOpen (_) {
//console.log(this.readyState); // open
var mediaSource = this;
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
fetchAB(assetURL, function (buf) {
sourceBuffer.addEventListener('updateend', function (_) {
mediaSource.endOfStream();
video.play();
//console.log(mediaSource.readyState); // ended
});
sourceBuffer.appendBuffer(buf);
});
};
function fetchAB (url, cb) {
console.log(url);
var xhr = new XMLHttpRequest;
xhr.open('get', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
cb(xhr.response);
};
xhr.send();
};
</script>
</body>
</html>
What am I doing wrong? I looked at tools ie.e MP4Box or QT-FastStart but they seem to be kind of old school. I would also be willing to change from MP4 to M3U8 playlist but then I don't know what MIME types to use.
At the ned of the day I am trying to play back a video/stream and hide the URL (origin) potentially using blob.
Thank you guys!

So, first, even though this code seems to be taken from mozilla documentation site, there are a few issues - you are not checking the readyState before calling endOfStream thus the error you get is valid, secondly, the play() call is blocked by the autoplay policy changes. If you add an error handler, you will actually see that the appendBuffer fails. Here is the updated snippet:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<video controls></video>
<script>
var video = document.querySelector('video');
var assetURL = 'https://ovation-blob-url-test.s3.amazonaws.com/AdobeStock_116640093_Video_WM_NEW.mp4';
// Need to be specific for Blink regarding codecs
// ./mp4info frag_bunny.mp4 | grep Codec
var mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource;
//console.log(mediaSource.readyState); // closed
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.error('Unsupported MIME type or codec: ', mimeCodec);
}
function sourceOpen (_) {
//console.log(this.readyState); // open
var mediaSource = this;
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
fetchAB(assetURL, function (buf) {
sourceBuffer.addEventListener('updateend', function (_) {
// console.log(mediaSource.readyState); // ended
if (mediaSource.readyState === "open") {
mediaSource.endOfStream();
video.play();
}
});
sourceBuffer.addEventListener('error', function (event) {
console.log('an error encountered while trying to append buffer');
});
sourceBuffer.appendBuffer(buf);
});
};
function fetchAB (url, cb) {
console.log(url);
var xhr = new XMLHttpRequest;
xhr.open('get', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
cb(xhr.response);
};
xhr.send();
};
</script>
</body>
</html>
So lets advance to next issue - the actual error. So, using chrome://media-internals/ we can see that the video actually fails to load do to incompatibility with the ISOBMFF format:
I am not familiar with Elastic Transcoder, but it seems that is it not producing an mp4 file suitable for live streaming. Also, if using mse, putting moov at the beginning is not enough, the video actually has to meet all of the ISOBMFF requirements - see chapters 3. and 4.
The working sample you mentioned is not a valid comparison since it uses the blob for the src, where the ISOBMFF rules do not apply. If it is fine for you to go that way, don't use MSE and put the blob directly in the src. If you need MSE, you have to mux it correctly.

Ok, so I got the original code example to work by encoding my MP4 videos with ffmpeg:
ffmpeg -i input.mp4 -vf scale=1920:1080,setsar=1:1 -c:v libx264 -preset medium -c:a aac -movflags empty_moov+default_base_moof+frag_keyframe output.mp4 -hide_banner
Important is: -movflags empty_moov+default_base_moof+frag_keyframe
This setup also scales the video to 1920x1080 (disregarding any aspect ratio of the input video)
However, based on the comments of the original post, I do believe there might be a more efficient way to generate the blob url and ingest into a video tag. This example was copied straight from https://developer.mozilla.org.
If anyone comes up with a better script (not over-engineered), please post it here.
Thank you #Rudolfs Bundulis for all your help!

Related

Auto-Redirecting after BigVideo.js video ends

I'm having trouble auto-redirecting after my video has ended using BigVideo.js. Not sure what's wrong here. Not only does this not redirect it completely breaks the player and the video does not play.
<script type="text/javascript">
var BV;
$(function() {
// initialize BigVideo
BV = new $.BigVideo();
BV.init();
BV.show('vids/video.mp4');
BV.getPlayer().on("ended", function() {
window.location = "http://www.google.com";
})
});
</script>
I tested your code locally and the redirection worked without any problems.
I guess it depends on the browser type/version or other environment factor.
Try to properly unload the video element by:
BV.getPlayer().on("ended", function () {
this.pause();
delete(this);
window.location = "http://www.google.com";
});
reference:
How to properly unload/destroy a VIDEO element
hope that will do the trick :)

XMLHttpRequest in a ContentScript from the Firefox SDK (Cross-Domain)

I am porting a chrome extension to firefox and want to keep as much code as possible. I am working with the sdk and I am new with JavaScript, so please bear with me if it is just a nooby mistake ;)
I need to get some stuff via a couple of XMLHttpRequests in content-scripts.
The "firefox-way" of doing things would be to use the sdk-request-api and work via messages between the main- and the content-script like so. Besides the fact that it would mean a lot of work for me to implement this throughout the whole addon, I also need to get binary data, which seems not to be possible.
The workaround for this is documented here. I would prefer to avoid this, since I think I read somewhere that it is a beta-feature right now and it seems to be pretty "work-aroundy".
Ideally I would like to implement it this way. In the upcoming Firefox 24 it should be possible to allow content scripts to access certain domains. Therefore I am using Firefox Aurora right now. I added the following code to my package.json:
"permissions": {
"cross-domain-content": ["http://mozilla.org"]
}
My main.js creates a panel when a button is clicked and loads the scripts into it:
var testPanel = require("sdk/panel").Panel({
contentURL: data.url("pages/background.html"),
contentScriptFile: [data.url("util/jquery-1.8.2.min.js"), data.url("pages/xhrTest.js")]
})
testPanel.show();
And this is my xhrTest.js:
var xhr = new XMLHttpRequest();
xhr.open("GET","http://mozilla.org",true);
xhr.onerror = function () {
console.log("Error");
};
xhr.onload = function () {
console.log("loaded");
}
xhr.send();
While debugging, it jumps from status 2 to 4 with an empty response and calls the "onerror". The status is 0, statustext is empty and I don't see any other indicators of what went wrong.
Now I don't know if this is still the same-origin-policy blocking me, or if I did something else wrong?
I'd really appreciate any help I can get :)
Thanks in advance,
Fabi
Hrm, I can't really see a glaring error. Here is an example add-on based on the docs that does work, at least it does for me in Firefox 24 Beta:
Main.js:
// main.js
var data = require("sdk/self").data;
var panel = require("sdk/panel").Panel({
height: 250,
contentURL: data.url("panel.html"),
contentScriptFile: data.url("panel-script.js")
});
panel.on("show", function(){
panel.port.emit("show");
});
require("sdk/widget").Widget({
id: "test-widget",
label: "Test-Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
panel: panel
});
Panel.html:
<!doctype HTML>
<html>
<meta charset="utf-8">
<head></head>
<body>
<pre id="forecast_summary"></pre>
</body>
</html>
Content script:
// panel-script.js
var url = "https://hn-test.firebaseio.com/articles/e5b10c82600b51732af584583a7f57c4a7c01bff.json";
self.port.on("show", function () {
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.onload = function () {
var element = document.getElementById("forecast_summary");
// formatting
var pretty = JSON.stringify(JSON.parse(request.responseText), null, ' ');
element.textContent = pretty;
};
request.send();
});
Package.json:
{
"name": "jp-crossdomain-xhr",
"fullName": "jp-crossdomain-xhr",
"id": "jid1-B2RaQxOBKox8wA",
"description": "a basic add-on",
"author": "",
"license": "MPL 2.0",
"version": "0.1",
"permissions": {
"cross-domain-content": ["https://hn-test.firebaseio.com"]
}
}
Github Repo

Push notifications using Node.js socket.io on apache web-server

I am trying to understand how this all push notifications works. I tried to do some test of push technology but so far i failed.
The base assumptions are:
1) use Apache web-server as the main application web-server (mandatory since all our code is using that)
2) Cross-Browser push notification server in node.js Technology (offered socket.io since it is crossed browser).
So far i failed and here is my code (p1.html):
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>P1</title>
</head>
<body>
<h1>P1</h1>
<section id="content"></section>
<script src="/socket.io.js"></script> <!--socket.io-->
<script src="/socket.js"></script> <!--socket.io-client-->
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
socket.on('notification', function (data) {
$('#content').append(data.message + '<br>')
});
</script>
</body>
</html>
and my server script (p1.js):
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, url = require('url')
app.listen(8080);
console.log("creating a connection");
io.sockets.on( 'connection', function ( socket ) {
console.log("runing time");
sendTimeMessage(socket);
});
function sendTimeMessage(socket){
console.log("in time");
var time= new Date().getTime();
console.log(time);
socket.volatile.emit( 'notification' , time );
setTimeout(sendTimeMessage, 5000);
}
function handler (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("");
}
function sendMessage(message) {
io.sockets.emit('notification', {'message': message});
}
i changed the IPs to local host for the example so i hope there is no mistake on the syntax.
when i run, the Apache web-server is the one that display the data and the idea is for the socket-io to update few fields.
current state:
1. If i don't add the socket.io-client js file i get reference error for socket.io-client
2. If i do add socket.io-client i get "ReferenceError: require is not defined
[Break On This Error] 'undefined' != typeof io ? io : module.exports
i can really need help understanding it, and making it work. i am also open minded to alternative solutions
i can really need help getting this done.
Working example, of what you want to achieve. First mistake is wrong javascript path on client-side, the right one is /socket.io/socket.io.js. Second mistake is use of socket.volatile which doesn't exist.
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, url = require('url')
console.log("creating a connection");
io.sockets.on( 'connection', function ( socket ) {
console.log("runing time");
sendTimeMessage(socket);
});
function sendTimeMessage(socket){
console.log("in time");
var now= new Date().getTime();
socket.emit('notification', {'message': now});
setTimeout(function() {
socket.emit('notification', {'message': "after 5s"});
},5000);
}
function handler (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end("<html><script src=\"/socket.io/socket.io.js\"></script> <!--socket.io--><script>io.connect().on('notification', function (data) {console.log(data)});</script></html>");
}
app.listen(8080);
Ok, i partially solved the with a huge help from the guys on IRC i created an:
1) HTML over Apache on port 80
2) live notification service update my HTML over port 8080
(there might still have code issue in the values arrived from the functions cause its not fully debuged)
p1.html (client)
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<section id="content"></section>
<script src="/node_modules/socket.io-client/dist/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
var socket = io.connect('http://10.10.10.1:8080');
socket.on('notification', function (from,msg) {
$('#content').append(msg.message + '<br>')
});
</script>
</body>
</html>
p1.js (service)
var io = require('socket.io').listen(8080)
console.log("creating a connection");
io.sockets.on( 'connection', function ( socket ) {
console.log("runing time");
var oldtime= new Date().getTime();
while (1){
var newtime= new Date().getTime();
if (newtime%5323==0 && newtime != oldtime){
oldtime = newtime;
console.log(newtime);
socket.emit( 'notification' , {'message': "the time is - " + newtime} );
}
}
});
enjoy
Thanks #yanger
I was helped by your code.
I want to add a comment.
But I can't use comment yet.
In my case, I want to make a real time alarm.
and I use 80 port web server and 81 port alarm server.
So I just use this code. (Client.js)
var socket = io.connect(':81');
It's totally working.
I wish someone would read this article and get help.

Loading audio via a Blob URL fails in Safari

Following code works in Chrome (22.0) but not in Safari (6.0)
<!DOCTYPE html>
<html>
<head>
<script>
function onGo(e) {
var fr = new FileReader();
var file = document.getElementById("file").files[0];
fr.onload = function(e) {
var data = new Uint8Array(e.target.result);
var blob = new Blob([data], {type: 'audio/mpeg'});
var audio = document.createElement('audio');
audio.addEventListener('loadeddata', function(e) {
audio.play();
}, false);
audio.addEventListener('error', function(e) {
console.log('error!', e);
}, false);
audio.src = webkitURL.createObjectURL(blob);
};
fr.readAsArrayBuffer(file);
}
</script>
</head>
<body>
<input type="file" id="file" name="file" />
<input type="submit" id="go" onclick="onGo()" value="Go" />
</body>
</html>
In Safari, neither callback (loadeddata nor error) is called.
The content used is an mp3 file, which is normally played back with audio tag.
Is there any special care needed for Safari?
Many years later, I believe the example in the OP should work just fine. As long as you somehow set the mime type when creating the blob, like the OP does above with the type property of the options passed in:
new Blob([data], {type: 'audio/mpeg'});
You could also use a <source> element inside of an audio element and set the type attribute of the <source> element. I have an example of this here:
https://lastmjs.github.io/safari-object-url-test
And here is the code:
const response = await window.fetch('https://upload.wikimedia.org/wikipedia/commons/transcoded/a/ab/Alexander_Graham_Bell%27s_Voice.ogg/Alexander_Graham_Bell%27s_Voice.ogg.mp3');
const audioArrayBuffer = await response.arrayBuffer();
const audioBlob = new Blob([audioArrayBuffer]);
const audioObjectURL = window.URL.createObjectURL(audioBlob);
const audioElement = document.createElement('audio');
audioElement.setAttribute('controls', true);
document.body.appendChild(audioElement);
const sourceElement = document.createElement('source');
audioElement.appendChild(sourceElement);
sourceElement.src = audioObjectURL;
sourceElement.type = 'audio/mp3';
I prefer just setting the mime type of the blob when creating it. The <source> element src attribute/property cannot be updated dynamically.
I have the same problem, and I spend a couple days troubleshooting this already.
As pwray mentioned in this other post, Safari requires file extensions for media requests:
HTML5 Audio files fail to load in Safari
I tried to save my blob to a file, named it file.mp3 and Safari was able to load the audio that way, but after I renamed the file to have no extension (just "file"), it didn't load.
When I tried the url created from the blob in another tab in Safari:
url = webkitURL.createObjectURL(blob);
it download a file right away called "unknown", but when I tried the same thing in Chrome (also on Mac), it showed the content of the file in the browser (mp3 files start with ID3, then a bunch of non-readable characters).
I couldn't figure out yet how I could force the url made of blob to have an extension, because usually it looks like this:
blob:https://example.com/a7e38943-559c-43ea-b6dd-6820b70ca1e2
so the end of it looks like a session variable.
This is where I got stuck and I would really like to see a solution from some smart people here.
Thanks,
Steven
Sometimes, HTML5 audio can just stop loading without any apparent reason.
If you take a look to the Media Events (http://www.w3schools.com/tags/ref_eventattributes.asp) you´ll see an event called: "onStalled", the definition is "Script to be run when the browser is unable to fetch the media data for whatever reason" and it seems that it should be helpful for you.
Try listening for that event and reloading the file if necessary, with something like this:
audio.addEventListener('onstalled', function(e) {
audio.load();
}, false);
I hope it helps!
Just use source tag in audio.
<audio controls>
<source src="blob" type="blobType">
</audio>

Phonegap: Photo not uploading

I'm trying to create a very basic photo upload feature. I've followed a lot of tutorials and examples online but I'm having some issues in actually getting it to work.
Currently I receive the following errors:
2012-03-26 17:37:02.107 Upload[84710:13403] fileData length: 72154
2012-03-26 17:37:02.119 Upload[84710:13403] File Transfer Error: unsupported URL
2012-03-26 17:37:02.121 Upload[84710:13403] [INFO] Error in error callback: org.apache.cordova.filetransfer1 = ReferenceError: Left side of assignment is not a reference.
This is my Phonegap HTML file:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>File Transfer Example</title>
<script type="text/javascript" charset="utf-8" src="cordova-1.5.0.js"></script>
<script type="text/javascript" charset="utf-8">
// Wait for PhoneGap to load
document.addEventListener("deviceready", onDeviceReady, false);
// PhoneGap is ready
function onDeviceReady() {
// Do cool things here...
}
function getImage() {
// Retrieve image file location from specified source
navigator.camera.getPicture(uploadPhoto, function(message) {
alert('get picture failed');
},{
quality: 50,
destinationType: navigator.camera.DestinationType.FILE_URI,
sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY
}
);
}
function uploadPhoto(imageURI) {
var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
var params = new Object();
params.value1 = "test";
params.value2 = "param";
options.params = params;
options.chunkedMode = false;
var ft = new FileTransfer();
ft.upload(imageURI, "hosting.domain.co.uk/ios/upload.php", win, fail, options);
}
function win(r) {
console.log("Code = " + r.responseCode);
console.log("Response = " + r.response);
console.log("Sent = " + r.bytesSent);
alert(r.response);
}
function fail(error) {
alert("An error has occurred: Code = " = error.code);
}
</script>
</head>
<body>
<button onclick="getImage();">Upload a Photo</button>
</body>
</html>
And this is my upload.php file:
<?php
print_r($_FILES);
$new_image_name = "namethisimage.jpg";
move_uploaded_file($_FILES["file"]["tmp_name"], "/var/www/vhosts/domain.co.uk/subdomains/hosting/httpdocs/ios/uploads".$new_image_name);
?>
Is there anything obvious that I'm doing wrong?
Thanks a lot
Jon
You are using fileURI to upload the photo that is why you are getting the unsupported file format error. This is because the fileURI will be something of the format file://localhost/xx1.jpg. This will be unsupported by the uploader function on the server side.
Javascript can't access the native file system
Javascript does not have direct access to the underlying file system therefore it cannot upload via file transfer in case of phonegap.
The Solution
Your best bet is to instead upload the base64 encoded string for the image. You can obtain the base64 encoded image by using the option navigator.camera.DestinationType.DATA_URL for destinationType. This will return the base64 encoded string. And this can be easily sent over json to the server with the associated metadata like jpg or png format and filename etc.
Take a look here of a successful use of phonegap and an online image hosting facility provided by imgur.
Good Luck and Cheers