Video's abort loading on internet explorer - javascript

I am developing this JavaScript game, that manages it's loading of assets, prior anything happens. At first, the preloader class loads up an assets json file, that contains all listed assets to load. This file contains links to aprox. 30 images, 8 json files and 5 videos. Every single asset apart from the video files load fine in every major browser (firefox, safari, explorer, chrome), but the loading of those 5 video files are aborted by internet explorer.
I'm using HTML boilerplate, maybe that has something to do with it.
This is what I get, in network view:
Link to full size image file
Sometimes, the first two videos load, sometimes none of them do. Here's an chunk of my code to load those videos:
case "ogv":
case "mp4":
item = document.createElement('video');
var itemSource = document.createElement('source');
item.id = 'vid'; item.width = '600'; item.height = '450'; item.controls = false;
if (extension == "mp4") {
itemSource.id = 'mp4'; itemSource.type = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
} else if (extension == "ogv") {
itemSource.id = 'ogv'; itemSource.type = 'video/ogg; codecs="theora, vorbis"';
}
itemSource.src = pathToAsset;
item.appendChild(itemSource);
item.addEventListener("canplaythrough", onVideoCanPlaythrough, false);
item.load();
break;
And here's the listener handler:
var onVideoCanPlaythrough = function () {
console.log("onVideoCanPlaythrough");
item.removeEventListener("canplaythrough", onVideoCanPlaythrough, false);
assets[assetID] = item;
callback.call();
}
The console.log("onVideoPlaythrough) does not fire a single time on Internet Explorer.
I have checked to make sure, that every other thing is correct (I get right url's in my pathToAsset variable and so on. This works on every other browser (except opera, which I haven't really tested yet), but not on IE
Can anyone suggest how to approach debugging of this sort of problem?

Apparently you initiate loading of the videos with video.play() statement, not video.load() on internet explorer 9. That's just great!

Related

Can't play HTML5 Video with Blob source on iOS devices

I have a React web app that gets the video URL from a server, then requests the video as a blob and tries to play this on an HTML video tag. I'm doing this because the client sometimes has issues with the internet and videos can stutter while playing, they'd rather wait longer for the video to load and then play it smoothly than have a choppy video. (I'm also saving the blob to IndexedDB as cache, but that's not related to the issue I'm having now, I'm just adding this as context but it has been disabled while I try to figure out this iOS problem)
I have a function to download the video, which then returns the Blob and a URL created from that blob object.
async function downloadVideo(videoUrl) {
return new Promise(function(resolve, reject) {
var req = new XMLHttpRequest();
req.open('GET', videoUrl, true);
req.responseType = 'blob';
req.onload = function() {
// Onload is triggered even on 404
// so we need to check the status code
if (this.status === 200) {
var videoBlob = new Blob([this.response], { type: 'video/mp4' });
console.log('Video blob?', videoBlob);
var vid = { objBlob: videoBlob, vidURL: URL.createObjectURL(videoBlob) };
// Video is now downloaded and converted into ObjectURL
resolve(vid);
} else {
reject('Video download failed with status ', this.status);
}
};
req.onerror = function() {
reject('Unable to Download Video');
};
req.send();
});
}
And then I have the element that plays the blob video:
<video
muted={true}
autoPlay={true}
loop={false}
onError={err => {
alert('Video load error. ' + err.target.error.iosMessage);
}}
src={downloadedVideo.url}
/>
That downloadedVideo.url is the blob object URL created on the DownloadVideo function
All of this works fine on desktop (Linux) and on Android, but the video doesn't play from the Blob on iOS devices. I've tried Safari, Chrome, and Firefox and the problem is the same.
on iOS I can get the video Blob and create an URL from it, but when I pass it as src it doesn't work, all I can get from the error (a MediaError object) is the code, 4, but the message is undefined.
If instead of the blob I pass the original video URL as src, it works on all devices, but then I can't cache the video and this feature will have to be dropped.
I've tried several videos and made sure encoding was compatible with iOS.
I could not find anything stating that iOS is not compatible with Blob URLs for video, so this should work, but I can't figure out why it doesn't.
Save the captured video with the type of "mp4"
IMPORTANT >>> new Blob(vid, {type: "video/mp4", })
const blobb = await new Blob(vid, {type: "video/mp4", }); // Important Line
I have a similar problem, but only on iOS 15.x (it works fine till iOS 14.5)
I think it's a bug on iOS 15.x - see also https://developer.apple.com/forums/thread/693447
There is a bug in webkit on iOS 15 builds, that do not include byte range headers to blob urls.
See: https://bugs.webkit.org/show_bug.cgi?id=232076 and Safari on iOS 15 inline video playback issues
As noted in the webkit issue, there is a workaround using a service worker.
https://bug-232076-attachments.webkit.org/attachment.cgi?id=442151
Mind though, service workers do not work in WKWebView.

Unpredicatable playback issues with videos recorded using Camera2

My team is working on a mobile web application using the Cordova framework, initially targeting Android. A feature of the application is to record video on the user's phone via a custom media capture plugin, save it locally, read it using the Cordova File plugin (cordova-plugin-file), and stream it to a Node JS server for distribution to other connected users via the Stream API.
Devices receiving the stream save each incoming chunk within an array of ArrayBuffers, and then convert this to a Blob via the Blob constructor:
let receivedChunks: ArrayBuffer[] = [];
// chunks of video data received from node.js server
// each chunk saved as ArrayBuffer
// ArrayBuffer[] treated as blob parts
const videoBlob = new Blob( receivedChunks, { type: 'video/mp4' });
We then use the File plugin to write this blob to the Android cacheDirectory for our application, and get a file:/// URL in order to load the video into an HTML5 <video> element. The app queues up playback of these <video> elements using the Media API and Media Events.
None of the published Cordova (or PhoneGap) plugins quite suited our UI requirements, so we wrote our own, based on the Camera2 API (we've sacked off support for Android 4.x and below for the time being). We based our plugin on the Google samples, and it was working fine until we ran into the same issue as referenced by another StackOverflow user: Camera2 video recording without preview on Android: mp4 output file not fully playable
Turns out there are some issues with Deep Sleep on Samsung Galaxy devices running Android 6.0 Marshmallow. We implemented the workaround I described in my answer to that question, which partly solved the problem, but left us with scrambled metadata that meant we lost device orientation hints (our app uses sensorLandscape to keep the UI the right way up, so we have to apply orientation fixes to recorded video in order to prevent them from playing back upside-down).
So we took our workaround a little further and decided to re-encode the corrected video:
private void transcodeVideo(String pathToVideo)
throws IOException {
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(pathToVideo);
int trackCount = extractor.getTrackCount();
MediaMuxer muxer = new MediaMuxer(pathToVideo+ "transcoded", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
HashMap<Integer, Integer> indexMap = new HashMap<Integer, Integer>(trackCount);
for (int i = 0; i < trackCount; i++) {
extractor.selectTrack(i);
MediaFormat format = extractor.getTrackFormat(i);
int dstIndex = muxer.addTrack(format);
indexMap.put(i, dstIndex);
}
boolean sawEOS = false;
int bufferSize = 256 * 1024;
int frameCount = 0;
int offset = 100;
ByteBuffer dstBuf = ByteBuffer.allocate(bufferSize);
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
muxer.setOrientationHint(DEFAULT_ORIENTATIONS.get(_savedVideoRotation));
muxer.start();
while (!sawEOS) {
bufferInfo.offset = offset;
bufferInfo.size = extractor.readSampleData(dstBuf, offset);
if (bufferInfo.size < 0) {
Log.d(TAG, "saw input EOS.");
sawEOS = true;
bufferInfo.size = 0;
} else {
bufferInfo.presentationTimeUs = extractor.getSampleTime();
bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;
int trackIndex = extractor.getSampleTrackIndex();
muxer.writeSampleData(indexMap.get(trackIndex), dstBuf,
bufferInfo);
extractor.advance();
frameCount++;
Log.d(TAG, "Frame (" + frameCount + ") " +
"PresentationTimeUs:" + bufferInfo.presentationTimeUs +
" Flags:" + bufferInfo.flags +
" TrackIndex:" + trackIndex +
" Size(KB) " + bufferInfo.size / 1024);
}
}
muxer.stop();
muxer.release();
}
This is where things get weird.
The re-encoded video seems to play back just fine on most other devices, including a rather long-in-the-tooth Moto G LTE (1st gen). However, when we stream and save more than a couple of videos at the same time on the Moto G, the re-encoded video stops playing properly. There's no audio or video, but the <video> element emits all the normal video events that we'd expect to see if the video was playing properly - in particular, the 'ended' event is fired after the expected duration.
If we only stream and save two videos, the Moto G can play the re-encoded video just fine. Other devices in the same session (all receiving the same set of videos delivered from the server) seem to have no problem with the S7's re-encoded video. If we remove the S7 from the set of devices in the same session, we sometimes see the same problem, but sometimes not - but it's 100% consistent when the S7 with the re-encoded video is involved.
Is there anything obviously wrong with our MP4 encoding? Is anyone aware of issues with simultaneously writing multiple files to the flash storage of a slower Android device like a Moto G? Has anyone else seen this odd playback behaviour, where a video element fires media events without actually playing audio or video?
I'm aware that this question may be a little lacking in focus, and there are a lot of variables involved (multiple possible points of failure in code, multiple devices, unclear on whether the problem is encoding, playback or something else), but if it rings a bell for anyone and they can provide a little insight then it would be greatly appreciated!

`Preload.js` failed to load some files on Android devices

PreloadJS stuck at a specific step when loading files on Android devices while everything works fine on a desktop browser and iPhone.
The loading process stopped at the final GIF file (as shown in the code). Why this GIF file could not be loaded?
This happened before with desktop browser, but with no error, But at that time it was caused by some non-standard mp3 files. How to deal with this kind of exception when failed to load/init a file?
Here is the code I used to load files.
var preload = new createjs.LoadQueue();
createjs.Sound.alternateExtensions = ["ogg"];
preload.installPlugin(createjs.Sound)
preload.installPlugin(createjs.SpriteSheet)
preload.addEventListener("fileload", updateLoadingProcess); // show loading process
showWelcomeText();
var resources = {
change: "assets/sound/change.mp3",
click: "assets/sound/click.mp3",
collide: "assets/sound/collide.mp3",
game_over: "assets/sound/gameover.mp3",
reset: "assets/sound/reset.mp3",
win: "assets/sound/win.mp3",
interface_assets: "assets/interface.png",
raining_serial: "assets/raining-serial.gif",
background: "assets/background.jpg",
text: "assets/text-" + LANG + ".gif",
};
var loadedResource = 0;
var manifest = [];
for(var i in resources){
manifest.push({id: i, src: resources[i] + _VER_ }); //add version to update cache
}
preload.loadManifest(manifest);
update
I found that some Android devices stopped at another point, the first image(interface.png), and I really don't know why because these browsers don't have a developer tool.
update
The problem is solved by not using XHR for these image files, although I still don't know why. var preload = new createjs.LoadQueue(false); could make it work.
there was a WebAudioPlugin bug with handling errors and a few issues with SoundJS and PreloadJS integration that have been fixed in the latest version SoundJS-Next and PreloadJS-Next. I would suggest trying those and seeing if you still have issues.
Hope that helps.

.find(".class:first") behavior with Opera and Safari

I'm using Soundmanager2 to play some audio files in a web site, but not using Flash.
It works fine with Firefox and Chrome, as they support ogg and mp3 respectively. However, it doesn't work with Opera 12.16. Theoretically, it supports ogg, and pass the condition if( supports_ogg_audio() ):
It is returning 1 in this function:
function supports_ogg_audio() {
var a = document.createElement('audio');
return !!(a.canPlayType && a.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''));
}
So it detects ogg support. But as I'm doing:
currentRow = thisPlayer.find(".total-row:first");
I get this error from the Opera console:
Unknown pseudo class
[id='total-playlist'] .total-row:first
So I'm guessing that this is the problem. How could select the first thisPlayer.find(".total-row") element with better browser compatibility?
It neither works in Safari5+ and IE9+
You need to use first-child selector instead of first. See information here.

How can I detect whether a browser supports MJPEG?

Modern browsers except IE handle MJPEG (Motion JPEG). Here is an example fiddle.
Can I detect support for MJPEG? I have looked through Modernizr in vain.
Modernizr only supports the following formats for detection right now: ogg, webm and h264.
The video element has a call called canPlayType(format) that would really be your only option (if it works for mjpg). Your detection logic would look something like this (not the format would be different).
var videoElement = document.createElement('video');
if(!!videoElement.canPlayType)
{
var browserConfidence = videoElement.canPlayType('video/mjpeg; codecs="insert, them"');
if(browserConfidence == "probably")
{
// high confidence
}
else if(browserConfidence == "maybe")
{
// low confidence
}
else
{
// no confidence... it definately will not play
}
}
Make sure you visit the W3C's information on canPlayType. It looks like the mime type should be "video/mjpeg" and not "video/mjpg" as you specified earlier.
I've tried the most obvious way to detect if the image could be loaded or not:
$output = $('<img id="webcam">')
.attr('src', src)
.load(function(){alert('ok')})
.error(function(){alert('error')});
In case image could be loaded load event will be fired, otherwise error. Checked this in recent Chrome and IE8. Works as expected.
Sadly for this you would need to use an ActiveX control to support mjpg in IE. See How to embed mjpeg file on a webpage.

Categories

Resources