I have a video directive which plays html5 video:
(function(){
angular.module('app.video')
.directive('demoVideo', demoVideo);
function demoVideo(){
return{
templateUrl: "videoTemplate.html",
controller: function(videoService, $sce){
var vm = this;
videoService.get().then(function(data){
vm.videoDataUrlMp4 = $sce.trustAsResourceUrl(data.video);//"http://pdl.vimeocdn.com/89496/595/203684545.mp4?token2=1418313891_4826d99475da5695f5d7999863fb212c&aksessionid=732c8c4ae38ae4aa"
});
},
bindToController: true,
controllerAs: 'video'
}
}
})();
The template is:
<script type="text/ng-template" id="videoTemplate.html">
<video id="video" controls="true">
<source id="mp4" ng-src="{{ video.videoDataUrlMp4 }}" type="video/mp4">
<p>Your user agent does not support the HTML5 Video element.</p>
</video>
The problem is that the video is not loaded. (I can see that the src is set to video's source, but it is not loaded. When I change the binding to be direct (not inside a callback), it does work!
I tried $scope.$apply() with no luck (throws an error).
What am I missing here?
tnx!
Have you tried returning the value?
Like this:
videoService.get().then(function(data){
vm.videoDataUrlMp4 = $sce.trustAsResourceUrl(data.video);//"http://pdl.vimeocdn.com/89496/595/203684545.mp4?token2=1418313891_4826d99475da5695f5d7999863fb212c&aksessionid=732c8c4ae38ae4aa";
return vm.video.DataUrlMp4;
});
Related
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 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>
I need to know how do I use the VgFullscreenAPI. The official documentation doesn't help.
This is what I have:
<vg-player
(onPlayerReady)="onPlayerReady($event)"
(onChangeFullscreen)="toggleFullscreen($event)">
<vg-play-pause #playBtn class="play-btn">
<span class="vg-icon-play_arrow"></span>
</vg-play-pause>
<vg-controls [vgAutohide]="true" [vgAutohideTime]="4" >
<vg-play-pause</vg-play-pause>
<vg-mute></vg-mute>
<vg-fullscreen class="ml-auto"></vg-fullscreen>
</vg-controls>
<video #media
[vgMedia]="media"
[attr.id]="post.id"
preload="none"
[poster]="post.thumbnail"
(click)="onVideoClick()"
loop>
<source [src]="post.source" type="video/mp4">
</video>
</vg-player>
toggleFullscreen($event){
console.log($event);
}
I have tried using the output event emitter (onChangeFullscreen) on vg-plater, vg-fullscreen, and video tags.
Documentation
The event is provided by the VgFullscreenAPI service inside VgPlayer, you can access it like this inside your component class:
#ViewChild(VgPlayer) vgPlayer: VgPlayer;
ngAfterViewInit(): void {
this.vgPlayer.fsAPI.onChangeFullscreen.subscribe((event) => {
this.toggleFullscreen(event);
});
}
Don't really know why they made it an EventEmitter inside the service. Doesn't seem like they really understand the new angular version yet :)
Now I have this list of videos on my side menu on my webapp. When any item on the list is clicked, an observable is fired and that helps change the "src" attribute of video tag. But it doesn't look like it's working.
Here's my html file:
<div class="video-container video">
<video width="400px" height="300px" controls (click)="toggleVideo()" #videoPlayer>
<source [src]="src" type="video/mp4" /> Browser not supported
</video>
</div>
And here's my .ts file
src;
mySubs: Subscription<string>;
constructor(private vid: VideosService) { }
ngOnInit() {
this.src = "...some default src";
this.mySubs = this.vid.getVodSub().subscribe(index => {
this.src = this.vid.videos[index].src;
});
}
ngOnDestroy() {
this.mySubs.unsubscribe();
}
As you and I can guess, the video element takes the initial src attribute value set by me. But when the "src" property is changed in the .subscribe() method, the video src doesn't change.
I've also tried setting src attribute via calling a function, like src="getMySrc()", but it doesn't work too.
How can I fix this? Thank you!
First of all, you should keep as much logic outside of templates as you are able to :)
I think you should map your observable to another one which will give back src of the video.
Try something like:
src;
mySubs: Subscription<string>;
actualVideo: Observable<string>
constructor(private vid: VideosService) { }
ngOnInit() {
this.actualVideo = this.vid.getVodSub().pipe(map(index => {
return this.vid.videos[index].src;
}));
}
Then use an async pipe in the template:
<source [src]="actualVideo | async" type="video/mp4" />
https://angular.io/api/common/AsyncPipe
I have multiple audio files that I want to stream based on the user selects. How do I do that? This is what I have so far and it doesn't seem to work.
*UPDATE: Made a few changes and now its claiming that audio.load(); is not a function. Can anyone tell me why that is? The Code is updated to reflect the changes.
JavaScript:
function updateSource(){
var audio = document.getElementById('oggSource');
audio.src =
'audio/ogg/' +
document.getElementById('song1').getAttribute('data-value');
audio.load();
}
HTML:
<audio id="audio" controls="controls">
<source id="oggSource" src="" type="audio/ogg"></source>
<source id="mp3Source" type="audio/mp3"></source>
Your browser does not support the audio format.
</audio>
<ul style="list-style: none">
<li>Sunday May 27, 2012
<ul style="display: none">
<li id="song1" data-value="song1.ogg">
<button onclick="updateSource();">Item1</button>
</li>
<li>Item2</li>
<li>Item3</li>
</ul>
</li>
</ul>
Item2 and Item3 I will want to play a different audio file when they are clicked on.
Try this snippet
list.onclick = function(e) {
e.preventDefault();
var elm = e.target;
var audio = document.getElementById('audio');
var source = document.getElementById('audioSource');
source.src = elm.getAttribute('data-value');
audio.load(); //call this to just preload the audio without playing
audio.play(); //call this to play the song right away
};
<ul style="list-style: none">
<li>Audio Files
<ul id="list">
<li>Death_Becomes_Fur.oga</li>
<li>Death_Becomes_Fur.mp4</li>
<li>rrs006.oga</li>
<li>sound_90.mp3</li>
</ul>
</li>
</ul>
<audio id="audio" controls="controls">
<source id="audioSource" src=""></source>
Your browser does not support the audio format.
</audio>
JSFiddle http://jsfiddle.net/jm6ky/2/
with jQuery:
$("#playerSource").attr("src", "new_src");
var audio = $("#player");
audio[0].pause();
audio[0].load();//suspends and restores all audio element
if (isAutoplay)
audio[0].play();
If you are storing metadata in a tag use data attributes eg.
<li id="song1" data-value="song1.ogg"><button onclick="updateSource()">Item1</button></li>
Now use the attribute to get the name of the song
var audio = document.getElementById('audio');
audio.src='audio/ogg/' + document.getElementById('song1').getAttribute('data-value');
audio.load();
Here is how I did it using React and CJSX (Coffee JSX) based on Vitim.us solution.
Using componentWillReceiveProps I was able to detect every property changes. Then I just check whether the url has changed between the future props and the current one. And voilĂ .
#propTypes =
element: React.PropTypes.shape({
version: React.PropTypes.number
params:
React.PropTypes.shape(
url: React.PropTypes.string.isRequired
filename: React.PropTypes.string.isRequired
title: React.PropTypes.string.isRequired
ext: React.PropTypes.string.isRequired
).isRequired
}).isRequired
componentWillReceiveProps: (nextProps) ->
element = ReactDOM.findDOMNode(this)
audio = element.querySelector('audio')
source = audio.querySelector('source')
# When the url changes, we refresh the component manually so it reloads the loaded file
if nextProps.element.params?.filename? and
nextProps.element.params.url isnt #props.element.params.url
source.src = nextProps.element.params.url
audio.load()
I had to do it this way, because even a change of state or a force redraw didn't work.
Found this spec note for those trying to change the src of a source element. Especially useful for libs like React where audio.load() causes render loop.
..modifying a source element and its attribute when the element is
already inserted in a video or audio element will have no effect. To
change what is playing, just use the src attribute on the media
element directly
<audio>
<source src='./first-src'/>
</audio>
To change the src
<audio src='./second-src'/>
<source src='./first-src'/>
</audio>
Try this:
Replace:
audio.load();
with:
audio.play();
change this
audio.src='audio/ogg/' + document.getElementById(song1.ogg);
to
audio.src='audio/ogg/' + document.getElementById('song1');