I use the HTML video element. As source I use a .mp4 video with sound. On my video element there are a few attributes. Default I use the attribute muted so there is no sound. With some JavaScript I add or remove the attribute muted by clicking on a button. So this works, when I inspect my markup and click the button I can see how the attribute muted will be added or removed (check out my snippet below).
My problem is, that when removing it, there is no sound. If I start the video file in an video player on my laptop or open it directly in the browser, I can hear the sound. Due to many posts, it should be possible to toggle the sound with this solution. I don't know why it doesn't have sound only when I use it in my video element with adding/removing the attribute muted. Any ideas?
const $ctx = $('.video');
const $video = $ctx.find('.video__video');
const $toggleSound = $ctx.find('.video__toggle-sound');
$toggleSound.click(this.handleVideoSound.bind(this));
function handleVideoSound() {
const attr = $video.attr('muted');
if (typeof attr !== typeof undefined && attr !== false) {
$video.removeAttr('muted');
} else {
$video.attr('muted', '');
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="video">
<video class="video__video" autoplay loop muted playsinline poster="/assets/img/video-poster.png">
<source src="/assets/video/video.mp4" type="video/mp4">
</video>
<button class="video__toggle-sound">Toggle video sound</button>
</div>
Replace your handleVideoSound method with the below code
function handleVideoSound() {
const attr = $video.prop("muted");
$video.prop("muted", !attr);
}
Hope it will help you. Below is the working code snippet.
const $ctx = $(".video");
const $video = $ctx.find(".video__video");
const $toggleSound = $ctx.find(".video__toggle-sound");
$toggleSound.click(this.handleVideoSound.bind(this));
function handleVideoSound() {
const attr = $video.prop("muted");
$video.prop("muted", !attr);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="video">
<video class="video__video" autoplay loop muted playsinline poster="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg">
<source src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4", type="video/mp4" />
</video>
<button class="video__toggle-sound">Toggle video sound</button>
</div>
Related
I need to pause a video if it is not in view
the below code works only for the first video in list
how to make it working for all .bvideo ?
<video class='bvideo' src='a.mp4' poster='a.jpg' preload='none' controls></video>
<video class='bvideo' src='b.mp4' poster='b.jpg' preload='none' controls></video>
<video class='bvideo' src='c.mp4' poster='c.jpg' preload='none' controls></video>
let io = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(!entry.isIntersecting){entry.target.pause();}
});
});
$(document).ready(function(){
io.observe(document.querySelector('.bvideo'));
});
Use querySelectorAll() method.
$(document).ready(function() {
let bvideos = document.querySelectorAll('.bvideo');
bvideos.forEach(bvideo => io.observe(bvideo));
});
I'm working on a page with a video player in which I'm trying to show vtt captions and get information from the cues in the <track> element.
Here's what's relevant for the player in HTML:
<div class="video">
<video id="vid">
<source src="Video.mp4" type="video/mp4">
<track kind="subtitles" src="Captions.vtt" srclang="en">
</video>
</div>
I had something like this in my JavaScript first, just to see what I was getting before manipulating anything in code.
var trackObject = $('track')[0].track;
trackObject.mode = 'showing';
console.log('Track cues:');
console.log(trackObject.cues);
console.log(trackObject.cues[0]);
The change to the mode attribute is done there because, if I set default to the <track> element in HTML, then the video doesn't appear in many browsers. Still don't know why.
What this prints to the console is the following:
However, when I expand the TextTrackCueList, I do see the cues:
This has only made sense to me if I assume that the cues have loaded into the element, but the length attribute hasn't been updated. But I still don't know what's that length I'm seeing at the end of the list, which shows the actual number of cues.
I haven't found any kind of load event on the text track, so this is what I did to make sure I can get the cues:
var trackObject = $('track')[0].track;
trackObject.mode = 'showing';
var waitForCues = setInterval(function() {
if (trackObject.cues.length > 0) {
var cueList = getTracks(trackObject)
// ...Do some processing with the cues...
clearInterval(waitForCues);
}
}, 40);
Why does this happen with the length attribute of the track element? How can I get rid of that waiting for the length to be greater than 0?
As an HTMLMediaElement, the <track> element supports the same global load and error events that any other HTMLElement does, so you can listen for those to determine whether your VTT is ready for business or not.
mytrack.addEventListener(`load`, evt => {
console.log(`good to go`);
const { track } = mytrack;
// force this track to become active so we can get the cues:
track.mode = "showing";
const { cues } = track;
console.log(`${cues.length} cues found`);
});
mytrack.addEventListener(`error`, evt => {
console.log(`yeah that's a problem`);
});
<video controls>
<source src="https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4" type="video/mp4">
<track
id="mytrack"
kind="captions"
src="data:text/plain;charset=utf-8,WEBVTT%0A%0A00%3A00%3A00.500%20--%3E%2000%3A00%3A02.000%0AThe%20Web%20is%20always%20changing%0A%0A00%3A00%3A02.500%20--%3E%2000%3A00%3A04.300%0Aand%20the%20way%20we%20access%20it%20is%20changing"
srclang="en"
label="English"
default="default">
>
</video>
I am making a mental health website in which there is a meditation area. there are two div cards and inside of each, there is one button that plays and stops music when clicked.
I am using script tags inside the html file for extra information.
Purpose:
when the buttons inside each of the two card div is clicked, a guided meditation audio should play.
there is a long audio and a short audio that comes in two formats of mp3 and ogg.
Problem:
one of the audios play perfectly but the second one doesn't work. meaning it wont play and stop when the button is clicked.
can you please check and tell me what's wrong.
<div class="main-box">
<div class="slot1">
<p class="line line1">this is the long music</p>
<audio id=rollSound loop>
<source src="sounds/long-medi.mp3" type="audio/mpeg">
<source src="sounds/long-medi.ogg" type="audio/ogg">
Your browser does not support the sound files. Please proceed by using other solutions.
<!--the obove text will only show if the users' browser does not play the two files. -->
</audio>
<button id=play>play/stop</button>
<script>
const rollSound = document.getElementById('rollSound');
const btn = document.getElementById('play');
btn.addEventListener("click", e => rollSound.paused ? rollSound.play() : rollSound.pause());
</script>
</div>
<div class="slot2">
<p class="line line2">this is for short music</p>
<audio id=shortsound loop>
<source src="sounds/short-medi.mp3" type="audio/mpeg">
<source src="sounds/short-medi.ogg" type="audio/ogg">
Your browser does not support the sound files. Please proceed by using other solutions.
</audio>
<button id=roll>play/stop</button>
<script>
const shortsound = document.getElementById('shortsound');
const btn = document.getElementById('roll');
btn.addEventListener("click", e => shortsound.paused ? shortsound.play() : shortsound.pause());
</script>
</div>
There is an error when executing your script because you can not declare var btn = a second time.
Instead change the following
const shortsound = document.getElementById('shortsound');
const btn = document.getElementById('roll');
btn.addEventListener("click", e => shortsound.paused ? shortsound.play() : shortsound.pause());
to something like this:
const shortsound = document.getElementById('shortsound');
const btn2 = document.getElementById('roll');
btn2.addEventListener("click", e => shortsound.paused ? shortsound.play() : shortsound.pause());
and it will work, see this jsfiddle:
https://jsfiddle.net/snw3950L/1/
i want to dynamically change the Urls of two Videos. My Problem is that the first Video's URL is getting Changed and plays correctly and the second Video just changes the Videos-Url without Playing it. The Second Video still shows the Placeholder-Poster.
Without changing the Video.source.src my Page looks like This:
<div class="container-fluid" id="container">
<div class="cocoen">
<video loop autoplay muted poster="img/placeholder_0.png">
<source type="video/mp4">
</video>
<video loop autoplay muted poster="img/placeholder_1.png">
<source type="video/mp4">
</video>
</div>
When trying to set the Video-Sources (yes, i know that both video-urls are the same, its just for test purposes :p)
var urls = ["img/small_1.mp4", "img/small_1.mp4"];
var sources = $("video > source").toArray();
sources[0].src = urls[0];
sources[1].src = urls[1];
startVideos();
Only the first (left) one is working:
But the Sources are correctly set on both videos.
I want to change the URLS more then Once, so just setting the URLS in the HTML isnt an Option.
If i set the src of video#1 to movie1 in html and video#2.src to movie2
and use JS to set video#1.src = movie2 and video#2.src=movie1
only the left video changes in display even tho the html has the correct src's.
I dont know if this Information is important, but this is how i start the Videos, after i set the URLS:
function reduceRetryOnError(array, callbackFunction, functionToRetry) {
success = array.reduce((acc, value) => acc && callbackFunction(value));
if (!success) {
console.log("Reduce failed: Retry in 300 ms");
setTimeout(functionToRetry(), 300);
}
}
function startVideos() {
function startVideo(video) {
if (!video) {
return false;
}
if (video.paused) {
video.play();
}
return true;
}
reduceRetryOnError($("video").toArray(), startVideo, startVideos);
}
I also tried to Pause and the start the Video again within the Starting Function.
Ty in advanced.
Well, as counter-intuitive as it sounds, muted tag is somehow ignored; check out the snippet below,
first one is rendered with react, the second one regular html; inspect them with your dev tools, and you see the react on doesn't have muted attribute; I already tried muted={true}, muted="true" but non is working.
function VideoPreview() {
return (
<div className="videopreview-container">
React tag:
<video
className="videopreview-container_video"
width="320"
height="240"
controls
autoPlay
muted
>
<source src="https://raw.githubusercontent.com/rpsthecoder/h/gh-pages/OSRO-animation.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
</div>
);
}
ReactDOM.render(<VideoPreview />, root)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
<hr/>
Regular html:
<video
width="320"
height="240"
controls
autoplay
muted
>
<source src="https://raw.githubusercontent.com/rpsthecoder/h/gh-pages/OSRO-animation.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
This is actually a known issue which has existed since 2016.
The video will be muted correctly, but the property will not be set in the DOM.
You can find multiple workarounds in the GitHub issue, although there might be pros and cons with any of them.
As mentioned by #FluidSense it is an open bug since forever.
I could achieve it like this:
import React, { useRef, useEffect } from "react";
export default function Video({ src, isMuted }) {
const refVideo = useRef(null);
useEffect(() => {
if (!refVideo.current) {
return;
}
if (isMuted) {
//open bug since 2017 that you cannot set muted in video element https://github.com/facebook/react/issues/10389
refVideo.current.defaultMuted = true;
refVideo.current.muted = true;
}
refVideo.current.srcObject = src;
}, [src]);
return (
<video
ref={refVideo}
autoPlay
playsInline //FIX iOS black screen
/>
);
}
muted works if you type it as muted="true". Using the string true sends the attribute to the DOM now
Here is how I dealt with it using dangerouslySetInnerHTML:
import React, { Component } from "react";
export default class VideoComponent extends Component {
state = {
videoStr: "",
};
componentDidMount() {
const { src } = this.props;
const videoStr = `
<video autoplay loop muted>
<source src=${src} type="video/mp4" />
</video>
`;
this.setState({ videoStr });
}
render() {
return (
<div
className={this.props.className}
dangerouslySetInnerHTML={{ __html: this.state.videoStr }}
/>
);
}
}
I would also note that some browsers like Chrome might have a limit for the file size a video can be. I was running my own videos on my website and when I inspected the page and looked under Sources I did not find the video I had used and been looking for. This forced me to investigate further. I realized the video that I was running was about 10.4mb. It was large relative to the usual payload of a website so I lowered the size to around 5mb and the video appeared on my site.
Some other information about my steps to finding a solutions was that I was using my localhost to run my React app. I also ran my React app on Safari which surprisingly displayed my video even when the size was 10.4mb. I'm guessing that browsers have different criteria for video sizes.
I ran into the same problem, so I made a custom HTML element that adds the muted video. Here is the custom muted video:
class MutedVideo extends HTMLVideoElement {
constructor() {
super();
this.muted = true;
// I also noticed that you used autoplay, so I added it too.
this.autoplay = true;
}
}
customElements.define("x-muted", MutedVideo, { extends: "video" });
And here the video preview.
// Notice how I removed the muted and autoPlay props and added the 'is' prop
function VideoPreview() {
return (
<video
is="x-muted"
width="320"
height="240"
controls
src="https://raw.githubusercontent.com/rpsthecoder/h/gh-pages/OSRO-animation.mp4"
>
Sorry, your browser does not support the HTML video tag
</video>
);
}
Here is a working demo
from my own project. (WORK)
const Header = () => {
const [isMuted, setIsMuted] = useState(false);
return (
<div className="header">
<video src={headerBg} autoPlay loop muted={isMuted? true : false} />
<div className="container" >
<div className="btn-mute" onClick={() => setIsMuted(!isMuted)}/>
</div>
</div>
);
};