I am making a web app with video playback and custom controls: a Next Video button and a Previous Video Button. My component looks like this:
const videos = [
'https://d3t1nqlebka5eu.cloudfront.net/videos3/82818a63-1972-4e39-b296-9cd3b85b0b39.mp4',
'https://d3t1nqlebka5eu.cloudfront.net/videos3/dd4dd6c5-95b7-41c2-b131-7b62392ad1b5.mp4',
'https://d3t1nqlebka5eu.cloudfront.net/videos3/29812506-e67d-4cab-b2b3-82461a4eadf1.mp4',
]
function App() {
const [videoIndex, setVideoIndex] = useState(0);
const h1Ref = useRef<HTMLVideoElement>(null);
return (
<div>
<DivButton onClick={() => {
setVideoIndex(getPrevIndex(videoIndex));
h1Ref.current!.load();
}}>
Prev
</DivButton>
{' '}
<DivButton onClick={() => {
setVideoIndex(getNextIndex(videoIndex));
h1Ref.current!.load();
}}>
Next
</DivButton>
<div>
<video id="video_player" autoPlay muted loop playsinline preload="" ref={h1Ref}>
<source id="video_player_source" src={videos[videoIndex]} type="video/mp4"/>
</video>
</div>
</div>
);
}
The problem is this: when I click Next or Prev buttons, the videos do switch between one another, but after every switch they are entering fullscreen mode on iOS. I don't need that, I need my controls around the video being played.
Is there a way to prevent that?
Assuming you already found an answer but for other people looking at this in the future, I suspect the issue was your capitalization of playsinline - in React you have to provide it as playsInline in order for it to be applied correctly, but that prop should prevent iOS from forcing videos into fullscreen when they start playing.
Related
I have multiple buttons and each button corresponds to a different video being played on the screen.
HTML:
<div class="video-container">
<video autoplay muted loop controls></video>
</div>
JS:
game.addEventListener('click', () => {
videoSource.setAttribute('src', `./assets/videos/${game.id}.mp4`);
});
The problem is if I have already downloaded the first video, when I click on button1 again the video is re-downloaded.
How do I implement caching here?
This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed last year.
I designed a website that has video.
I want the video to start playing automatically every time Windows scrolls and reaches the video section. And when the user scrolls to a lower or higher section, video stop. And when you return to the video section, the video will play automatically.How to do this with JavaScript for a number of videos on one page.On the advice of a friend, I used "Intersection Observer API". This code works for one video, but does not work for multiple videos on one page.thanks.
const video = document.querySelectorAll("video");
for (let i = 0; i < video.length; i++) {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) {
video.pause();
} else {
video.play();
}
});
}, {});
observer.observe(video);
}
<div>
<div class="video-container">
<video controls>
<source src="http://itp.nyu.edu/~rnr217/HTML5/Week3/video/testopen.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
</div>
<div>
<div class="video-container">
<video controls>
<source src="http://itp.nyu.edu/~rnr217/HTML5/Week3/video/testopen.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
</div>
Use the intersection API, so that once the video element comes into viewport you can play it and stop it once it leaves the viewport.
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
I have 8 videos on a page. on each video element i have add some things like sound control and description.
Specifically, the sound control mutes and umutes the video on click and also changes its icon accordingly. Hoever, when the video goes full screen, the browser uses its own controls for sound. So, for example if a user watches a video on mute, then goes full screen, and then turns on sound, and then exits full screen, the sound is still on but the sound control suggests it is not.
So i'd like to run a function every time any video on the page exits full screen, to update the sound icon.
Here's my html for the video element. I have 8 identical video elements on the page:
<div class="section-element video-mockup" onmouseenter="hoverIn($(this))" onmouseleave="hoverOut($(this))">
<video loop muted playsinline preload="metadata" class="video-onhover" controlsList="nodownload" onclick="clickPlay($(this))" ondblclick="toggleFullscreen(this)">
<source src="/wp-content/uploads/wysiwyg/webm/Video.webm" type="video/webm">
<source src="/wp-content/uploads/wysiwyg/webm/Video.mp4" type="video/mp4">
</video>
<div class="section-inner video-overlay">
<hr class="whiteLine">
<div class="videoControls">
<div class="overlay-columns description">
<p class="overlay-text"></p>
</div>
<div class="overlay-columns buttons">
<button class="videoButtons sound-button" title="Sound" onclick="toggleSound(this);"><ion-icon name="volume-off"></ion-icon></button>
<button class="videoButtons reset-button" title="Restart" onclick="expandVideo(this);"><ion-icon name="expand"></ion-icon></button>
</div>
</div>
</div>
</div>
So I am trying to update the <button class="videoButtons sound-button" title="Sound" onclick="toggleSound(this);"> on any video that exits fullscreen.
Here's my code for that:
$('video.video-onhover').on('fullscreenchange', function($this) {
var thisVideo = $this.target;
console.log(thisVideo);
var soundButton = thisVideo.parentElement.querySelector('button.sound-button');
if (thisVideo.muted) {
soundButton.innerHTML = '<ion-icon name="volume-off"></ion-icon>';
} else {
soundButton.innerHTML = '<ion-icon name="volume-high"></ion-icon>';
}
});
I added the console.log to see if the function is being called, but it doesn't seem to run. i am guessing there is something wrong with the fullscreenchange event but i can't find any other way. Any ideas?
I want to update the source tag in a HTML5 video element so that when I click a button, whatever's playing switches to a new video.
I have a Clip component that returns an HTML5 video element, with the source URL provided via props.
function Clip(props) {
return (
<video width="320" height="240" controls autoPlay>
<source src={props.url} />
</video>
)
}
I also have a Movie component, which contains multiple URLs, each corresponding to a section of the movie. It also contains a position attribute, which acts like an iterator by remembering which section is currently playing.
class Movie extends Component {
constructor() {
super();
this.state = {
sections: [
'https://my-bucket.s3.amazonaws.com/vid1.mp4',
'https://my-bucket.s3.amazonaws.com/vid2.mp4'
],
position: 0
};
}
render() {
const sections = this.state.sections
const position = this.state.position
return (
<div>
{position}
<Clip url={sections[position]} />
<button onClick={() => this.updatePosition()}>Next</button>
</div>
)
}
updatePosition() {
const position = this.state.position + 1;
this.setState({ position: position });
}
}
The Movie component renders a Clip component and a "Next" button. When the Next button gets clicked, I want to update the position attribute and re-render the HTML5 video element using the next URL from sections.
As of now, when I hit Next the HTML5 video source tag updates, but the element continues playing the video from the previous URL. Can anyone help me figure out how to reset the video element?
Update: I created a JSFiddle, which you can see here.
Update 2: Updating the src attribute on the video element works!
Quick and dirty awnser: Add a key prop to <Clip> or <video>, e.g.:
function Clip({ url }) {
return (
<video key={url}>
<source src={url} />
</video>
);
}
Recommended awnser: Trigger a load event for the video element whenever there's a new URL, e.g.:
function Clip({ url }) {
const videoRef = useRef();
useEffect(() => {
videoRef.current?.load();
}, [url]);
return (
<video ref={videoRef}>
<source src={url} />
</video>
);
}
Explanation: The video initially doesn't change because in essence you're only modifying the <source> element and React understands that <video> should remain unchanged, so it does not update it on the DOM and doesn't trigger a new load event for that source. A new load event should be triggered for <video>.
The dirty answer works because when you change the key of a React element, React understands that's a whole new element. It then creates a new element in the DOM which naturally will have its own load event triggered on mount.
Changing the src of <source /> doesn't seem to switch the video for some reason. This isn't a react issue I don't think. Probably just how <source /> works. Maybe you have to call .load() on the element again. But it's just easier to set it directly on the element itself.
See the comment to the top answer: Can I use javascript to dynamically change a video's source?
You can set src directly on element instead:
function Clip(props) {
return (
<video width="320" height="240" src={props.url} controls autoPlay>
</video>
)
}
Bind the URL in the src property of Video tag and not Source Tag
<video autoplay loop muted playsinline="true" webkit-playsinline="true" [src]="videoSrc" type="video/mp4">
Add a parent div to second video
My code:
{isMobile ? (
<video
autoPlay={true}
loop
className="moviles"
muted
playsInline
poster="/totto/kids.png"
>
<source src="/totto/losmoviles.webm"></source>
<source src="/totto/losmoviles.mp4"></source>
</video>
) : (
<div>
<video
autoPlay={true}
loop
className="moviles2"
muted
playsInline
poster="/totto/portada.jpg"
>
<source src="/totto/moviles.webm"></source>
<source src="/totto/moviles.mp4"></source>
</video>
</div>
)}
You can use the key attribute :
<video key={videoUrl} autoPlay width="100%">
<source src={videoUrl} type="video/mp4"></source>
</video>
If the video's key attribute change, the video component will be re-mounted
I'm currently working on a page for playing different videos when you click an element. While it works beautifully on the computer, of iOS devices it does not. The problem is that when the element, in this case a button, is clicked, it shows the video but does not start playing, as it should. The script is
$(document).ready(function(){
$('#video_1, #video_2').hide();
$('.icon_1').click(function(){
$('#video_2').fadeOut(function(){
$('#video_1').fadeIn();
});
});
$('.icon_2').click(function(){
$('#video_1').fadeOut(function(){
$('#video_2').fadeIn();
});
});
$('.icon_1').click(function(){
$('.video_2').get(0).pause();
$('.video_2').get(0).currentTime = 0;
$('.video_1').get(0).play();
});
$('.icon_2').click(function(){
$('.video_1').get(0).pause();
$('.video_1').get(0).currentTime = 0;
$('.video_2').get(0).play();
});
});
and the html is
<button><div class="icon_1" id="mediaplayer" onclick="play">cadillac</div></button>
<button><div class="icon_2" id="mediaplayer2" onclick="play">nike</div></button>
<div id="video_1">
<video class="video_1" width="50%" height="50%" controls poster="http://www.birds.com/wp-content/uploads/home/bird.jpg" >
<source src="http://video-js.zencoder.com/oceans-clip.mp4" type="video/mp4" />
</video>
</div>
<div id="video_2">
<video class="video_2" width="50%" height="50%" controls poster="images/BKG_JohnGT.png">
<source src="images/01.mp4" type="video/mp4" />
</video>
</div>
It anyone could give me a function that could mak this happen, tht would be great
iOS does not support more than one video element in a page at one time. It doesn't even give you an error message - it will merely display the poster image (or first frame) and then fail to play, just as you describe.
Unfortunately, you can't do a true cross-fade, but you can come close. Start with only one video element attached to the DOM. When switching from one video to another, you can fade the current video out, and then when it's done, remove it and add the second video. Apple has provided some details and code samples on how to do this.
In theory, you should be able to grab a snapshot of the video frame in a canvas and swap that in for the video and fade the canvas out, but iOS doesn't support capturing video frames in a canvas either.
These and some other non-standard behaviors are described well in this article.