I'm using JW Player to show a Flash video (although it will soon have HTML5 sources where browser support allows).
Until the user takes an action on the page, the video needs to be invisible (but loaded). Once they take that action, the video div is shown and I'd like to play() the video as immediately as possible.
Here's my setup() call. <div id="video"> is hidden in my CSS file, as is JW Player's <div id="video_wrapper"> (both set to display: none; initially).
jwplayer("video").setup({
playlist: [
{
sources: [
{ file: 'http://example.com/video.flv' }
]
}
],
controls: false,
wmode: 'transparent'
});
And some time later, I'm doing this:
$('#video').show();
$('#video_wrapper').show();
jwplayer().play();
I don't get any errors in the console and the video plays fine if I don't first hide the containing divs in my CSS file.
Does JW Player not fire its setup() method on a hidden element? And, if not, how should I achieve the result I want?
See if the solution here works for you:
Unable to play audio when JWPlayer is hidden
Position the containing div so that it is no longer visible, then call the setup function on it. Your show function will have to be a little more complex to change the display settings back to how you want them to be.
Related
I'm using the Themepunch Revolution slider in a project, which shows a single video slide in HTML 5.
When I click on it, it pauses, which I don't want.
The <video> element in the page is generated by the slider plugin.
Here's what I tried so far:
$('body').on('click', 'video', function(e) {
e.preventDefault();
e.stopPropagation();
return false;
});
This is the code in the slider library:
html5vid.find('video, .tp-poster, .tp-video-play-button').click(function() {
if (html5vid.hasClass("videoisplaying"))
video.pause();
else
video.play();
})
I also tried catching the pause event, but it never fires:
$('body').on('pause', 'video', ...);
For Revolution Slider 6.x, it's easier, just select the video layer option > Content > (Scroll down) Advanced Media Settings > Set "No Interaction" off
This will disable the click to pause/play also remove controls, you end up with a playing video with no interactions, also don't forget to set Loop Media on for complete experience
Revolution Slider No Interaction Setting to prevent controls and stop click for play/pause:
Hey it is 2019 but anyone who look for solution is that :
Put transparent shape layer onto video layer as full width and height.
Make sure put this layer one step above the video layer as showing below(this shape looks like it below the video layer but in rev slider animation settings the more bottom the more up on the front-end i hope i make it clear :)
Layer positions on rev slider animation settings
Try
html5vid.find('video, .tp-poster, .tp-video-play-button').unbind('click');
Replace html5vid with whatever element the script is looking to find in.
EDITED
...or better yet, try to unbind click on the video element as follows:
$('video').unbind( "click" );
I have a video (let's call it composite video) composed by multiple other videos concatenated using some pattern. For example, see the screenshot of the videos below, composed by two and four other videos, respectively:
However, I need to display it differently: One main, larger, video and N-1 video thumbnails, where N is the total number of videos. Here are this other display corresponding to the videos above:
To display the main I'm using a combination of HTML and CSS to position the video I want in the larger div. It runs smoothly, no matter the number of videos in the composite videos.
To display the thumbnails, I'm using <canvas> to draw the parts I want:
video.addEventListener('play', function() {
(function loop() {
drawThumbnails();
setTimeout(loop, 1000 / 30); // drawing at 30fps
})();
}, false);
function drawThumbnails() {
for (var i = thumbs.length - 1; i >= 0; i--) {
drawThumbnail(thumbs[i]);
};
}
function drawThumbnail(thumb) {
var thumbNumber = Number(thumb.id.match(/\d+/g));
var canvasContext = thumb.getContext('2d');
var thumbCoordinates = getVideoCoordinates(thumbNumber);
var srcX = thumbCoordinates.column * videoWidth;
var srcY = thumbCoordinates.row * videoHeight;
canvasContext.drawImage(
video, srcX, srcY, videoWidth, videoHeight, // Source
0, 0, thumb.width, thumb.height); // Destination
}
It was working well for 3 (sometimes 4) videos. However, as the number of videos in the composite video increases, the videos in the thumbnails start to freeze and run not in a smooth way. This is probably happening because there's too much image processing being done at the same time.
I think the proper way to do it is, somehow, using <video> and methods specific for videos, not for images. I've also tried to use the same src in the multiple <video> tags (one for each thumbnail) and add eventListeners to play/pause the videos in the thumbnails once the main video is played/paused. That's not very efficient, particularly because videos can get out of sync sometimes, when seeking/buffering.
Is there a way of using only one video in multiple <video> tags and use only one of them (in my case, the one that contains the main video) to control all the others? In case there's no way of doing that, is there an alternative approach for my problem?
Thanks a lot,
P.S. Having multiple, separated, videos is not an option in my situation. It would take a very long time to process the input video and divide it in multiple videos.
You can certainly reference the same video across multiple video elements. Cloning the original and appending them as thumbnail videos might alleviate some of the tedium.
Iterating over the thumbnails and .play()ing them should be fine so long as you set their currentTime with that of the main video prior to playing, to minimize drift. There may be some need to wait for canplay to fire on the main video and/or the thumbnails depending on the exact experience you're looking to deliver.
If each thumbnail is given a parent container you could possibly position the video element serving as your thumbnail such that only the portion of the video you care to see is visible, clipping the rest.
FWIW, CSS masking might be of interest to you as a performance optimization if it helps the compositing performance.
You will need to manually coordinate playing/pausing all of the video elements, but that should be easy enough to do with a facade object that handle the play pause of all the "linked" video elements.
I know I'm posting late, and you may have already found an answer. However, if anyone else comes across this question, here is my answer:
You can use multiple video elements with the same source. The way to do it is with css.
.wrapper {
height: /*height of one video*/;
width: /*width of one video*/;
overflow: hidden;
}
video {
position: relative;
top: /*height offset*/;
left: /*width offset*/;
}
And HTML
<div class="wrapper">
<video src="myvideo.mp4"></video>
</div>
So, if I was doing the top right video, and each one was 250px by 250px, I would set my wrapper height and width to 250px and my video top to 0px and my video left to 250px
What's the format of the main video? Is it an on demand mp4/webm file?
If you still want to go with your approach of grabbing frames and paint them but is facing performance issues, consider using web workers for the heavy jobs. Here you can find some examples of video/canvas manipulation with web workers.
functionality:
User is able to access the video page from the main menu. Video will be played automatically, at this moment, the video is not in full screen and for aesthetic purposes, there are no control buttons in the video frame.
Secondly, when user clicks on the video, it will be displayed as full-screen, and when user clicks on the full-screen video, the video will exit the full screen and reverts back to the original video frame size.
What has been done:
I have created the video frame by using the jQuery .jPlayer. And the video is playing automatically when the video page is loaded.
I have attached the following code:
function Footprints() {
console.log("Footprints");
//Main video player for video page
$("#Footprints_1").jPlayer({
ready: function() {},
swfPath: "javascript",
supplied: "webmv, ogv, m4v",
loop: true,
size: {
width: 1450,
height: 750
}
}).bind($.jPlayer.event.play, function() { // pause other instances of player when current one play
$(this).jPlayer("pauseOthers");
});
$("#Footprints_1").jPlayer("setMedia", {
//set m4v tag to array Footprints VideoList
m4v: "http://www.jplayer.org/video/m4v/Finding_Nemo_Teaser.m4v"
}).jPlayer("play");
$("#Footprints_1").show();
$("Footprints_1").click(function() {
console.log("fullscreen")
$("#Footprints_1").requestFullscreen();
})
}
<div id="Footprints_Page" align="center" style="position:absolute; background-repeat: no-repeat; display: none; top:0px; left:0px; ">
<!--Video Player-->
<div id="Footprints_1" style="position:absolute; top: 180px;"></div>
</div>
Hence, when you run the code, it is showing this:
Issue:
At this point, when I click on the video frame when the video is playing, nothing happens. The video doesn't expand to the full screen.
Hence, how am I able to make the video expand to full screen when I click on the video and and when the video is clicked it reverts back to the original size.
Thanks.
You are currently fighting two three issues.
The first is you are not using jplayer's event system. that is why the clicks are being ignored.
I added a bind.click to your jplayer decleration, and the clicks responded.
.bind($.jPlayer.event.click, function() {
console.log("fullscreen")
$("#Footprints_1").requestFullscreen();
});
See this Fiddle.
The second issue is that you are calling requestFullscreen() on a jQuery object. It is not part of the jQuery API. You need to be calling it on an HTML element.
document.getElementById("jp_video_0").requestFullscreen();
So, the above example should probably be: (untested)
.bind($.jPlayer.event.click, function() {
console.log("fullscreen")
document.getElementById("jp_video_0").requestFullscreen();
});
If you want to have some control over padding and placement, request fullscreen on the container, and you can use CSS.
document.getElementById("Footprints_1").requestFullscreen();
However, the third issue is that not all browsers seem to use the same method of requestFullscreen(). See Mozilla docs. For me the following worked in Chrome:
.bind($.jPlayer.event.click, function() {
console.log("fullscreen")
var elem = document.getElementById("Footprints_1");
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen();
} else if (elem.mozRequestFullScreen) {
elem.mozRequestFullScreen();
} else if (elem.webkitRequestFullscreen) {
elem.webkitRequestFullscreen();
}
})
This Post has more info on fullscreen from jQuery as well as info on x-browser issues.
Hope it helps.
Edit: jsFiddle can't demonstrate the Fullscreen API, because I can not add the required 'AllowFullscreen' attribute to their iframe. If you view the frame source of the jsFiddle result, you can just save that as an HTML document, and it should work.
I am using the youtube iframe javascript api, and my videos are not playing in ios7. I've noticed that there is a play button within the iframe which is hidden by youtube's own stylesheets (or rather, set to a height and width of 1px !important). If I use safari's debugger with the ios7 simulator to remove these styles, the play button is visible, and when clicked, allows the video to play in ios.
The problem is, I cannot write a style in my stylesheets which overrides this behavior! How can I solve this issue? Attached is a screenshot of the offending style, and below is my code to initiate the player:
var videoOptions = {
'controls': 0,
'playsinline' : 1,
'showinfo': 0,
'html5':1,
'modestbranding': 1,
'autoplay': 0,
'rel': 0,
'enablejsapi' : 1,
//'origin': window.location.origin,
'wmode': 'opaque'
};
$scope.jsPlayer = new YT.Player('story-video-player-container', {
height: '100%',
width: '100%',
videoId: $scope.currentVideo.youtube_id,
events: {
'onReady': $scope.onPlayerReady,
'onStateChange': $scope.onPlayerStateChange,
'onPlaybackQualityChange': $scope.onPlaybackQualityChange
},
playerVars: videoOptions,
});
I've tried changing all of the videoOptions to show all controls / info / branding / etc, nothing works.
This is a known issue that Google says is "fixed" but other developers (including ourselves) insist is not. I've referenced your question there. You may want to follow this but report and add your own voice to the discussion.
At this point, this appears to be something controlled entirely on Youtube's end because it sets the size of the video tag inside the html5-video-container to 1px.
In our case, we have the iframe embedded on the page, and then a button that runs javascript to display the hidden div element so the video appears, and also trigger the YouTube API play event to make the video play (example: http://www.3708colet.com).
But Google says this is the same as "autoplay" and is disabled by iOS (it's also evidently disabled by Android Chrome--in our tests it's broken there too). Instead of playing, in iOS at least, it shows a 1px white square in the upper left corner of our container where the iframe is. And if we click that, it triggers "interaction" with the video and loads the video (doesn't work for Android). So there are no errors, but youtube's page just doesn't make that video large enough to fill the iframe area.
So, here's what I'm trying to do:
I want to load a video into a video element, but not have it played in the "normal" way.
Using a timed interval, calculated according to the movie's framerate, I want on each iteration to
A. Manually advance the video one 'frame' (or as close as possible to that).
B. Draw that frame into a canvas.
Thereby having the video "play" inside the canvas.
Here's some code:
<video width="400" height="224" id="mainVideo" src="urltovideo.mp4" type="video/mp4"></video>
<canvas width="400" height="224" id="videoCanvas"></canvas>
<script type="text/javascript">
var videoDom = document.querySelector("#mainVideo");
var videoCanvas = document.querySelector("#videoCanvas");
var videoCtx = null;
var interval = null;
videoDom.addEventListener('canplay',function() {
// The video's framerate is 24fps, so we should move one frame each 1000/24=41.66 ms
interval = setInterval(function() { doVideoCanvas(); }, 41.66);
});
videoDom.addEventListener('loadeddata',function() {
videoCtx = videoCanvas.getContext('2d');
});
function doVideoCanvas() {
videoCtx.drawImage(videoDom,0,0);
//AFAIK and seen, currentTime is in seconds
videoDom.currentTime += 0.0416;
}
</script>
This works perfectly in Google Chrome, but it doesn't work in an Iphone's Safari;
The video frames does not get drawn at all to the canvas.
I made sure that:
The video events I hooked into does get triggered (did 'alerts' and they were shown).
I have control over the canvas (did a 'fillRect' and it filled).
[I also tried specifying dimensions in the drawImage - it didn't help]
Is drawImage with a video object not applicable at all in Iphone Safari...?
Even if I'll manage to find a way to capture the video frames, there are also some other issues in the Iphone's browser:
Access to the currentTime property of the video is only granted once the video has started playing (in a standard way). I thought about maybe somehow "playing it hidden" and then capturing, but didn't manage to do that. Also thought of maybe somehow start playing the video and then immediately stop it;
There doesn't seem to be any way to forcefully start the playing of a video in the IOS Safari. video.play(), or autoplay doesn't seem to do anything. Only if the user taps the "play circle" on the video then the video starts playing (taking all over the screen, as usually with videos on the IPhone's browser).
Once the video plays - the currentTime property does get forwarded. On the video itself. When you pause the video and go back to the normal html page - you can see the frames on the video element changing. Though, in a slow phase (unlike in Google Chrome, where the rate seems to be smooth enough to make it look like it's playing) - in the iphone it looks to be a rate of something like 2-3 frames per second maybe. It stays the same even if I try changing the interval timing, I guess there's a minimum time limit that the browser on the IPhone can handle.
"Bonus question" :)
- When the frames on the video element progresses from the event - the circle "play button" is visible on the video element (since it is not actually 'playing'). Is there anyway to hide it and make it invisible?
This has been tested on Iphone 3GS (with both 3G and Wifi) and Iphone 4, both running IOS 5, both having the same results as described.
Unfortunately I don't have an iOS device to test this, but I don't think you need to actually capture the video frames in the way that you're attempting using the currentTime property. The usual process looks something like this:
create a video element without controls (omit the controls attribute)
hide the element
when the video is playing draw it to the canvas on an interval
As you've discovered, iOS devices do not support autoplay on HTML5 video (or indeed audio) but you can create a separate control to initiate playback of the video using the play() method.
This approach should solve the issue you're having with the play button being visible since in this case you are actually playing the video.
I don't believe the loadeddata event is called on iOS, try the loadedmetadata event instead. I also found it necessary on iOS to call the videoDom.load() method after setting videoDom.src.
For my use case, I need to do a "dRAF" (double requestAnimationFrame) after the seeked event to ensure something was actually drawn to the canvas rather than a transparent rectangle.
Try something like:
videoDom.onloadedmetadata = () => {
videoCanvas.height = videoDom.videoHeight
videoCanvas.width = videoDom.videoWidth
videoDom.currentTime = 0
}
videoDom.onseeked = () => {
// delay the drawImage call, otherwise we get an empty videoCanvas on iOS
// see https://stackoverflow.com/questions/44145740/how-does-double-requestanimationframe-work
window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
videoCanvas.getContext('2d').drawImage(videoDom, 0, 0, videoCanvas.width, videoCanvas.height)
videoDom.currentTime += 0.0416
})
})
}
videoDom.load()
From this gist