Blazored Video
The easiest html5 video
implementation for Blazor applications.
Changelog
2022-24-12 Version 1.1
- Bump dotnet version to 6.0 as 3.x and 5.x are now out of support.
- Add standard Methods and Properties (big thanks to https://github.com/JPVenson) and Async versions (for Server/WASM). (Issues #17 #9)
- Include video element id ("Id") and component object ref ("Video") in VideoState and VideoEventData (Issue #19) for identifying which component triggered an event.
Getting Setup
You can install the package via the nuget package manager - just search for Blazored.Video. You can also install via powershell using the following command.
Install-Package Blazored.Video
Or via the dotnet CLI.
dotnet add package Blazored.Video
Internet Explorer 11
This package can be used with Internet Explorer 11, but some special care should to be taken.
- Only Blazor Server works with IE11. Blazor WebAssembly does not work with any IE version. See this
- A polyfill is necessary for this component to work. See this page for an explanation on how to install and use it. The sample project for Blazor Server uses the polyfill and thus should work on IE11
Taking these things into account, Blazored.Video
will work on IE11.
Note: The sample projects in this repo have IE11 support baked in.
Note: This package is no longer tested on IE 11 - as IE support has been dropped - it may work - it's up to you to test it.
Add Imports
Add the following to your _Imports.razor
@using Blazored.Video
@using Blazored.Video.Support
Usage
Please checkout the sample projects in this repo to see working examples of the features in the Video component.
Displaying a Video
Just use BlazoredVideo in place of any video
tags.
<BlazoredVideo Play="OnPlay"
class="w-100"
style="max-width:800px;"
controls="controls">
<source src="videos/elephants.mp4" type="video/mp4" />
</BlazoredVideo>
This will render the html (id is auto-generated by default but you can supply your own)
<video class="w-100" id="361044add13e438cb3de299cd74272a6" controls="controls" _bl_796fa517-712e-4cf5-b8d6-7a4d940f2947=""><!--!-->
<source src="videos/elephants.mp4" type="video/mp4">
</video>
Media Events
This component maps every media event on the video tag using either an Action or an EventCallback - depending on your preference.
Note: EventCallback
events will automatically call StateHasChanged
on the parent component, while Action
events do not - it is your choice which you use for any event
Action | EventCallback | Description |
---|---|---|
Abort | AbortEvent | Fires when the loading of an audio/video is aborted |
CanPlay | CanPlayEvent | Fires when the browser can start playing the audio/video |
CanPlayThrough | CanPlayThroughEvent | Fires when the browser can play through the audio/video without stopping for buffering |
DurationChange | DurationChangeEvent | Fires when the duration of the audio/video is changed |
Emptied | EmptiedEvent | Fires when the current playlist is empty |
Ended | EndedEvent | Fires when the current playlist is ended |
Error | ErrorEvent | Fires when an error occurred during the loading of an audio/video |
LoadedData | LoadedDataEvent | Fires when the browser has loaded the current frame of the audio/video |
LoadedMetadata | LoadedMetadataEvent | Fires when the browser has loaded meta data for the audio/video |
LoadStart | LoadStartEvent | Fires when the browser starts looking for the audio/video |
Pause | PauseEvent | Fires when the audio/video has been paused |
Play | PlayEvent | Fires when the audio/video has been started or is no longer paused |
Playing | PlayingEvent | Fires when the audio/video is playing after having been paused or stopped for buffering |
Progress | ProgressEvent | Fires when the browser is downloading the audio/video |
RateChange | RateChangeEvent | Fires when the playing speed of the audio/video is changed |
Seeked | SeekedEvent | Fires when the user is finished moving/skipping to a new position in the audio/video |
Seeking | SeekingEvent | Fires when the user starts moving/skipping to a new position in the audio/video |
Stalled | StalledEvent | Fires when the browser is trying to get media data, but data is not available |
Suspend | SuspendEvent | Fires when the browser is intentionally not getting media data |
TimeUpdate | TimeUpdateEvent | Fires when the current playback position has changed |
VolumeChange | VolumeChangeEvent | Fires when the volume has been changed |
Waiting | WaitingEvent | Fires when the video stops because it needs to buffer the next frame |
Event Data
You are in control of the data sent with every event, if the video
element you have on your page has the data, you can request it for any event.
Event data is requested by supplying a dictionary to the VideoEventOptions parameter.
[Parameter] public Dictionary<VideoEvents, VideoStateOptions> VideoEventOptions { get; set; }
Each entry defines the VideoStateOptions
you require to be populated for any VideoEvents
value.
VideoEvents
is an enum of the Media Event names (see table above).
VideoStateOptions
is a struct listing all the properties of the video
element.
Property | Description | Notes |
---|---|---|
AudioTracks | Returns a List<AudioTrack> object representing available audio tracks | This is not exactly obsolete, but not yet implemented, sorry |
Autoplay | Returns whether the audio/video should start playing as soon as it is loaded | |
Buffered | Returns a TimeRanges object representing the buffered parts of the audio/video | This is not exactly obsolete, but not yet implemented, sorry |
Controls | Returns whether the audio/video should display controls (like play/pause etc.) | |
CrossOrigin | Returns the CORS settings of the audio/video | |
CurrentSrc | Returns the URL of the current audio/video | |
CurrentTime | Returns the current playback position in the audio/video (in seconds) | |
DefaultMuted | Returns whether the audio/video should be muted by default | |
DefaultPlaybackRate | Returns the default speed of the audio/video playback | |
Duration | Returns the length of the current audio/video (in seconds) | |
Ended | Returns whether the playback of the audio/video has ended or not | |
Error | Returns a MediaError object representing the error state of the audio/video | |
Loop | Returns whether the audio/video should start over again when finished | |
MediaGroup | Returns the group the audio/video belongs to (used to link multiple audio/video elements) | |
Muted | Returns whether the audio/video is muted or not | |
NetworkState | Returns the current network state of the audio/video | |
Paused | Returns whether the audio/video is paused or not | |
PlaybackRate | Returns the speed of the audio/video playback | |
Played | Returns a TimeRanges object representing the played parts of the audio/video | |
Preload | Returns whether the audio/video should be loaded when the page loads | |
ReadyState | Returns the current ready state of the audio/video | |
Seekable | Returns a TimeRanges object representing the seekable parts of the audio/video | |
Seeking | Returns whether the user is currently seeking in the audio/video | |
Src | Returns the current source of the audio/video element | |
StartDate | Returns a Date object representing the current time offset | |
TextTracks | Returns a TextTrackList object representing the available text tracks | This is not exactly obsolete, but not yet implemented, sorry |
VideoTracks | Returns a List<VideoTrack> object representing the available video tracks | This is not exactly obsolete, but not yet implemented, sorry |
Volume | Returns the volume of the audio/video |
Let's look at an example.
Suppose you want to subscribe to the Play
and TimeUpdate
events so that you can remember the position in the video and restore it when the user comes back to this video.
There are two pieces of information we might want from the video
- The name/url of the video file
- The current timeline position
So, we create a dictionary and populate it with those options
Dictionary<VideoEvents, VideoStateOptions> options = new Dictionary<VideoEvents, VideoStateOptions>();
options[VideoEvents.TimeUpdate] = new VideoStateOptions { CurrentTime = true, CurrentSrc = true };
options[VideoEvents.Play] = new VideoStateOptions { CurrentSrc = true };
Note: I don't really need the CurrentSrc property in both events - it's just to show having more than one selected.
Now, we can pass that to the BlazoredVideo
component.
<BlazoredVideo PlayEvent="OnPlay" TimeUpate="OnTimeUpdate"
VideoStateOptions="options"
class="w-100"
style="max-width:800px;"
controls="controls">
<source src="videos/elephants.mp4" type="video/mp4" />
</BlazoredVideo>
Notice: I have use an EventCallback for the play
event and an action for the timeupdate
event - because in this case I don't want a re-render every time the timeupdate
fires
This will render the html
<video class="w-100" id="361044add13e438cb3de299cd74272a6" style="max-width: 800px;" controls="controls" _bl_796fa517-712e-4cf5-b8d6-7a4d940f2947=""><!--!-->
<source src="videos/elephants.mp4" type="video/mp4">
</video>
Now, every time the play
or timeupdate
media events fire,
they will retrieve the currentSrc
and/or currentTime
properties from the video
element and pass that data in a VideoState
struct.
void OnPlay(VideoState state)
{
var url = state.CurrentSrc;
// do something with this
}
void OnTimeUpdate(VideoState state)
{
var url = state.CurrentSrc;
var currentTime = state.CurrentTime;
// do something with this
}
Calling Standard Methods
** Added 2022-12-24 **
The component now supports four standard methods
Method | Description | Notes |
---|---|---|
StartPlayback | Start playback from C# code | await videoRef.StartPlayback() |
PausePlayback | Pause playback from C# code | await videoRef.PausePlayback() |
ReloadControl | Reload media from C# code | await videoRef.ReloadControl() |
CanPlayMediaType | Check media type from C# code | bool isSupported = await videoRef.CanPlayMediaType("video/webm") |
Get/Set Standard Properties
** Added 2022-12-24 **
The component now supports most standard properties directly from C# code.
Example - WASM only
int duration = videoRef.Duration
Note: Attempting to read/write Properties from Blazor Server will throw a runtime exception telling you to use the Async versions instead. I would advise always using the async Get/Set methods as they are able to use Asynchronous or Synchronous (under WebAssembly) calls at runtime automatically, while the Properties are Synchronous only.
Example - Remote JS (Server) and WASM
int duration = await videoRef.GetDurationAsync()
Customising the html
The Video can be customised using standard CSS techniques.
All attributes are passed straight through to the HTML.