I have created a set of custom navigation elements for a video, to simulate walking around a building (for fire training).
When an overlay is pressed, the routine jumps to a predetermined spot using vidElmt.currentTime = 5; (for example). This works fine on Windows (Chrome, FF, and IE 11) and on the iPad (Safari), but when I try it on my Android phone (4.3, using Chrome or the built-in browser), the videos jump to the wrong spots. For example, if I set it to jump to the 5 second spot, it looks like it jumps to 2, 3 or 4 second spot.
I know some people may point out that I could be trying to jump to a spot not yet loaded, but I know the parts of the video I'm jumping to are definitely already loaded.
I wonder if it's something about my video format (mp4). I've searched to see if anyone has problems with the video tag and currentTime on Android, but I'm not finding anything.
Here is my demo link, if you want to check it out for yourself: http://eqsim.com/fesim/ when the playhead arrives at side/location, it should loop that specific section, and you can press the arrow keys that are lit up to change locations.
I'd appreciate any suggestions!
-jonathan
I suspect you might need to keep querying the video in an interval until the frame you want is seekable. A full working example can be found in this jsbin, but the relevant code is this:
function isSeekable(time) {
for (var i=0; i<video.seekable.length; i++) {
if (video.currentTime > video.seekable.start(i) && video.currentTime < video.seekable.end(i)){
return true
}
}
return false
}
Does that work for you? It seems to work in my Android 4.3 stock browser. If not, can you tell me more about how you encoded your video? Adding more keyframes could help with frame accuracy.
Related
A bit of a strange one - I'm working with the YouTube iFrame API for the first time, building a skin for a customers site.
I've followed the code examples provided by Google/YouTube (https://developers.google.com/youtube/player_parameters?playerVersion=HTML5#IFrame_Player_API).
The issue is that when clicking the play button, which calls player.playVideo(), under some circumstances it will play, but mostly, it just appears to refresh the video with no errors logged in the console. The video will fade to black as if it was about to play, but instead it fades back to the video "poster" with the play button.
You can view the entire code here - https://codepen.io/james-morton/pen/BEZGvm
I've tried various different things such as instead of using:
function onYouTubePlayerAPIReady() {
.. I tried this as per other examples to no avail
window.onYouTubePlayerAPIReady = function() {
Again, to be clear, the controls sometimes works, and sometimes it doesnt - same machine, same browser, same video - I've tried other videos and the same result. It's really inconsistent as it sometimes works.
Any ideas?
Edit:
After further debugging using the below:
function onPlayerStateChange(event){
console.log('State Change: ' + event.data);
}
I can see that for when it doesn't load, the player's state has changed from -1 (Unstarted) to 3 (Buffering), and then back to -1 (Unstarted) when clicking the play button.
It turns out the issue appears to be with CodePen - having transferred all of the code to my own environment, it works flawlessly with no playback issues via the controls.
Having reviewed https://css-tricks.com/play-button-youtube-and-vimeo-api/ that use a very similar setup, the problem was easily replicated on CodePen, and comments (all the way back from 2014) describe the issues that I experienced.
Hopefully this will be useful to others that spot this.
This is a strange one! I didn't quite 'solve' it but I have some feedback. On running your code, at first I couldn't get it to play at all (by either the middle 'YT' play button or by the custom play button), but when I used your 'ff' button (when it hadn't yet started to play), there was obvious signs that it had being activated. I changed the z-index in the yt-player from 2 to -2 and then was able to use the middle button to start play. After the initial play, I had no problem using the custom buttoms (pause/play worked fine) - and I refreshed and tried it multiple times, each time with success.
The one big issue is starting the first video play with the custom play button. You could maybe autostart it (perhaps with a delay?) to circumvent having to use the middle button? I did inspect the widths of the buttons (to see if maybe padding / overlap) may be affecting the play button but didn't find anything. I did notice that when I played the video that it was rising slightly from it's initial position so I tweaked the css a tiny bit (only a very slight tweak). Here's my codepen link (It's not that different from yours..) I hope this helps .. if even a bit.
I'm implementing a video player using VideoJS. Two key functions of this video player are:
a) If the user leaves the page, resume the video at that point when they come back or on refresh
b) Include HLS (h.264/mp4) support to provide better video quality depending on the connection.
The API for saving and retrieving a user's timestamp is already in place, and using the excellent HLS plugin, the video player works almost fine in all browsers as expected. The following code is used to initialize the player and jump to the saved time:
videojs.options.flash.swf = '../video-js/video-js.swf';
var player = videojs(videoId);
supportHLS = videojs.Hls.isSupported();
player.ready(function() {
[[event listeners for media controls]]
this.on('seeked', function() { console.log('seeked');});
this.on('seeking',function() { console.log('seeking');});
var PLAYER_LOADED = 'loadedmetadata';
if(!supportHLS) { PLAYER_LOADED = 'canplay';}
this.one(PLAYER_LOADED, function() {
this.one('canplay', function() {
this.play();
});
this.currentTime(savedPosition);
lastViewed = savedPosition;
});
});
(Reason for the roundabout logic: Chrome had issues with playing the video before the new data (after the seek) had loaded, which caused a number of problems with the data in the buffer. Also, Safari 7.1 would break if you tried this during the 'loadedmetadata' event)
However, there's still one problem, specific to Safari. The loading spinner doesn't always go away when you refresh the page. Examining the logs and listeners seems to indicate that the 'seeking' and 'seeked' events fire at about the same time, but in different orders; the problem always arises whenever 'seeked' fires first, and never occurs when 'seeking' is first. Furthermore, any seeking after the video is playing removes the spinner, so it has to be caused by the initial seek.
It's interesting that Safari supports HLS streaming natively, yet consistently causes the most problems with this player implementation. This is the last Safari bug to iron out, but though it's small it still has a negative impact on user experience.
What causes Safari to fire the 'seeked' and 'seeking' events out of order like this? What can I do to work around it, or is there a cleaner solution for what I'm trying to accomplish?
I am working on a functionality explained below-
Once a video is loaded/with a button click, it has to play in reverse. The target devices are smart phones and tablet devices. I am trying to do this using HTML5 tag and read about the playBackRate attribute. Further down, I am using the HTML5 stuff to generate my mobile apps using Phonegap.
Here's a link I found interesting but partially working -
http://www.w3.org/2010/05/video/mediaevents.html
The playbackrate, when changed doesn't do anything except it pushes the video back, by whatever number is given there.
I read it here that when playBackRate is set to -1, the reverse playback should happen.
I am not clear on how to exactly implement this. Does the playbackrate actually do this reversing? or should I opt on doing something else?
NEW LINE HERE:
I am almost there.. found a working example here. But this is not working when I am trying it on my system. I am not sure where I am making it wrong.
This is an old thread so I'm not sure how useful the following will be.
The Mozilla developer notes point out that:
Negative values [for playbackRate] don't currently play the media backwards.
Same goes for Chrome, but Safari on Mac works.
This page from w3c is great at observing and understanding events:
http://www.w3.org/2010/05/video/mediaevents.html
I took the jsfiddle you mentioned and added some extra controls for fast forward/rewind speeds:
http://jsfiddle.net/uvLgbqoa/
However, though this works fine for me with Chrome/Firefox/Safari, I should point out that it doesn't really address your key questions.
Firstly, the approach assumes that negative playback rates don't work (which at the time I write this, is largely true AFAICS). Instead, it fakes it by calculating and setting the current time in the video:
function rewind(rewindSpeed) {
clearInterval(intervalRewind);
var startSystemTime = new Date().getTime();
var startVideoTime = video.currentTime;
intervalRewind = setInterval(function(){
video.playbackRate = 1.0;
if(video.currentTime == 0){
clearInterval(intervalRewind);
video.pause();
} else {
var elapsed = new Date().getTime()-startSystemTime;
log.textContent='Rewind Elapsed: '+elapsed.toFixed(3);
video.currentTime = Math.max(startVideoTime - elapsed*rewindSpeed/1000.0, 0);
}
}, 30);
}
Chrome handles this quite seamlessly, even playing snippets of audio as it goes.
Secondly, I think you want to play the video in reverse as soon as the page loads. I can't imagine a use case for this, but the first issue I see is that the whole video will need to be downloaded prior to playback, so you'll need to wait - but download probably won't happen until you start playing. So you could set the currentTime to near the end and wait for the canPlay event, and then start playing in reverse. Even then, this seems very awkward.
I think there are these broad options:
Use a native video widget rather than HTML. I'm guessing (without checking) that the native API supports reverse playback.
Generate a proper reversed video and play it as normal. For example, on a server somewhere use a program like ffmpeg to reverse the video. Then your app downloads the video and plays it normally, which looks to the user like reverse.
Assuming it really does make sense to have an application that plays a video in reverse when you load it, then I'd personally go for #2.
I have a scenario where I have search results that contain video content. Each video item in the results has a thumbnail sized video player, so up to 10 html 5 video players can exist per result set. When the user clicks the thumbnail, the video goes fullscreen and automatically plays the video. When the user exits fullscreen, the video pauses.
This all works great on iOS devices, but on android I have significantly more even handling to worry about. Here's the logic as I have it now:
goFullScreen: function (ev) {
var el = ev.target,
isVideoFullscreen = el.webkitDisplayingFullscreen;
el.webkitEnterFullScreen();
// the approach below is the only way I could get reliable fullscreen detection on android
$(window).bind("resize", function (e) {
if (isVideoFullscreen != el.webkitDisplayingFullscreen) {
isVideoFullscreen = el.webkitDisplayingFullscreen;
if (isVideoFullscreen) {
el.load();
el.play();
} else {
el.pause();
}
}
});
}
Even though iOS does not need all of this even handling, it still works fine. The problem with android is that when I exit fullscreen, the video pauses, but the poster image is replaced for the video I just paused with a still from the video (to be expected), but all subsequent videos in the result set have their poster image replaced with an ugly video icon. As a result, the thumbnails just look like broken videos. But if you tap them they still go fullscreen and play just fine.
I'm testing on a Galaxy Nexus and a Galaxy SII. I can say that the el.pause() is not responsible, if removed the video will continue playing in the thumbnail and all video tags below it will still have the broken poster icon.
This works as expected on desktop webkit browser and on iOS devices. Only experiencing this issue on android 4+ devices. Also remember that the EnterFullscreen request has to happen in the scope it's in. Calling out of this scope will prevent it from working due to security restrictions on mobile devices. I've pretty much exhausted all ideas so I'm looking here to hopefully get a few more.
Any suggestions would be greatly appreciated.
I've given up on trying to solve all of the bugs and quirks in Android. Instead, I'm just linking directly to the mpeg4 videos from the thumbnails. So no more video tags, no more event handling.
The only side effect is that some versions of android display a dialog on how you want to play the video, which is not ideal but better than any alternative I could find. Fortunately the iOS experience is consistent no matter what approach I take.
We're writting a Canvas demonstration Real Time Strategy (RTS) game in HTML5/JavaScript and have everything pretty much working. However, in Chrome (very latest version) the sound keeps stuttering and eventually just gives up. The code runs just fine in the latest Firefox, IE9 and Safari (though no sound at all on iOS4 iPhone/iPad but apparently that's a commercial decision by Apple). You can see for yourself on the link below just get more than a few sounds at once to cause the issue.
http://www.enterprisewarfare.com/Play.aspx
The simplified sound play code is below, note each sound exists 4 times (AUDIO_CHANELS_PER_FILE) to simulate more than one channel. Adjusting this number does not cause the sound loss any earlier or later so it is not to do with reaching the end of the array or playing the same audio object again. We've tried both OGG and MP3 file formats and everything works in IE9 (MP3) and Firefox (OGG) without issue. We've also tried seeking the file back to the begining to no avail.
this.PlaySound = function(sId)
{
var iSoundMapIndex;
var asoundChannels;
if(sId == null || sId.length == 0) return;
// Grab sound channels array
iSoundMapIndex = this.SoundMap[sId];
asoundChannels = this.Sounds[iSoundMapIndex];
if(asoundChannels == null)
{
this.World.AddMessage("Unable to find sound \"" + sId + "\".");
return;
}
// play the next in sequence
asoundChannels[this.SoundChannel[iSoundMapIndex]].volume = 1;
asoundChannels[this.SoundChannel[iSoundMapIndex]].play();
this.SoundChannel[iSoundMapIndex]++;
if(this.SoundChannel[iSoundMapIndex] == this.AUDIO_CHANNELS_PER_FILE) this.SoundChannel[iSoundMapIndex] = 0;
}
It seems like this is an issue with chrome and chromium. I'd suggest looking trough the bug reports and dev answers on them or just wait for it to be resolved and ignore the problem meanwhile.
It's a shame that no-one with more experience than me in javascript made any suggestions concerning a workaround. I've upvoted the question in the hope you'll find some help.
It turns out this was a bug in Chrome and It appears this has now been fixed. Still some issues with sound loading and more than one channel but the complete breakdown of sound seems to have been resolved.