I'm currently expiring an issue. I try to serve a video file via FileStreamResult. Basically my code looks like that:
public IActionResult Video([FromQuery] int fileId)
{
var sfs = _sourceService.GetStreamByFileId(fileId);
return new FileStreamResult(sfs,new MediaTypeHeaderValue("video/mp4")) {EnableRangeProcessing = true};
}
In the next step I try to present the video on a website. For this example, I've tried the basic HTML5 Video Player.
<video controls width="640" height="264">
<source src="UrlToVideoAction" type="video/mp4">
Everything works fine. But if I now try to skip to a later position which isn't buffered at the time, the video player stops buffering/seeking. My Application doesn't throw any exception.
Then I tried to analyse the requests and responses. I noticed that my browser sends the following range header property when I skip to a specific position which isn't buffered:
Range: bytes=101318656-
It seems like the browser tries to fetch the whole ressource. The video player stops playing and if I retry to skip to a new position no further request will be sent. I've tested that behaivour with Firefox, Chrome and Edge. My tested file is about 250 mb. I also tested several other files all in MP4 format (x264, aac)
So my approach basically is to serve a video file in ASP.NET Core which should be able to skip to a specific position.
Thanks for any help.
Related
I have two live videos feeding an encoder which creates H.264 chunk files and an HLS manifest which is being served by an apache web server.
A browser page using video.js shows a player. Pressing "play" on the browser properly plays the video. It works well.
However, if we change video sources (by flipping the switch in the picture below), there is a considerable delay (10 seconds) before the new content is displayed in the player. I'd like to get that to 3 seconds.
It appears that video.js and/or the HTML5 player in browser is buffering that amount of content. (if you delete the files on the web server, kill apache, or even pull the ethernet cable, the video keeps on playing!)
A button on the web page controls the switch. When clicked, I would also like to clear or reset the player so that it immediately re-reads the index.m3u8 manifest and downloads the new chunks.
So far, haven't found anything promising searching the internet or in the video.js API docs. There are lots of articles on API calls for fetching the current buffer percentage but cannot find any API for clearing it altogether.
Any ideas?
The encoder is set for 3 second chunks and the playlist depth is set for 10 entries.
I had a similar problem. Since i could not find a reliable API for this, i came up with a rather dirty workaround to clear the buffer:
var ctime = player.currentTime();
player.currentTime(0);
player.currentTime(ctime);
This currently works for me in all major browsers.
I've searched a bit here on SO to find a way to show instagram video using the public api ?__a=1 method. I've found a question that have pointed me into the right direction but not at all.
after I get the user media, I'm checking in my vue app if the resource is a video or an image and if is a video I show an html5 player where I'm binding the url that is obtained form the public json api. What I'm facing is that the player will not reproduce the video, but if I use the url into the browser, an html5 player is loaded with the related video that will start playing.
The video urls returned are something like this one:
"https://scontent-mxp1-1.cdninstagram.com/v/t50.2886-16/117420353_635186773777278_7723572524374891239_n.mp4?_nc_ht=scontent-mxp1-1.cdninstagram.com&_nc_cat=106&_nc_ohc=nI6tYDeag-0AX8MtmoL&oe=5F3C077B&oh=a47046b1aabf223f16c4c66526e20e57"
I've tried to remove all the part after the .mp4 file extension but this will not work, so I suspect that all the url is needed. Is there a way that I can use to reproduce video in my app?
After many tryes unfortunately I didn't figured out how to use my own HTML5 player so I've used a simple solution. An <iframe> with the url set will let the vido play into the app, this exclude me from the ability to remove the download button or controls from the player but at the moment it's the only way I can implement to achieve my scope.
(1) Your link works okay for me in a video tag:
<video width="640" height="480" >
<source src="https://scontent-mxp1-1.cdninstagram.com/v/t50.2886-16/117420353_635186773777278_7723572524374891239_n.mp4?_nc_ht=scontent-mxp1-1.cdninstagram.com&_nc_cat=106&_nc_ohc=nI6tYDeag-0AX8MtmoL&oe=5F3C077B&oh=a47046b1aabf223f16c4c66526e20e57"
type="video/mp4">
</video>
(2) It even works okay in this random demo that uses vue.js.
With no demo page of your problem the solution is a guess...
Make sure that your own site URL starts https:// or else change the video src to http://...etc.
Make sure your server (settings?) isn't somehow blocking you from loading the file.
If still failing, show us the problem via some link to your testing page.
I'm running a VueJS application that displays a full screen story of videos. I don't create as many tag as number of media in my story : I'm just changing component video sources each time I play a new video.
But it looks like Safari (Desktop & mobile) still does not cache HTML video once loaded : when I'm playing again a previous media, Safari is downloading again the asset. Instead of getting from cache like Chrome does.
The same issue has already been reported here but sill no correct answer.
Safari even stops downloading the final bytes video (producing a sort of timeout) when we go back and forth quicky in the story, so the story looks stuck.
Here's an example link.
Does anyone know a good alternative that avoids re-downloading video data at each play on Safari ?
Partial solution
Found myself a workaround that works pretty well if video is small size - all video are less than 3Mb in my case.
The trick is to use js fetch API to download full video, then stream it into video tag.
const videoRequest = fetch("/path/to/video.mp4")
.then(response => response.blob());
videoRequest.then(blob => {
video.src = window.URL.createObjectURL(blob);
});
Contrary to video src attribute, fetch API will get video data from cache if the same video was already fetched before.
Here a codepen demo that can be tested in Safari desktop/mobile (when NOT in private mode).
Pro : Video are now pulled from cache in Safari !
Con : You can't start the video until full data has been downloaded. That's why this solution can be used only for small video (like < 5Mb), else your users may wait a while before being able to play the video.
My video src is an AWS presigned request url, it expires in x amount of time. The video will start playing just fine in video.js. For large video files after the brief url expiration time, changing the seek bar causes a network error because the original src link has expired. How do you refresh the src with another unexpired presigned url without restarting from the beginning of the video? I don't want the video to go back the beginning.
So far I have found that you can capture the change of the seek bar by listening for the event 'timeupdate' and in the passed event testing for e.manuallyTriggered.
Thanks
i had this same issue today. i'm using plyr instead of videojs, so i'm not sure if you can do this exact thing, but my solution was:
bind an error handler to the player for when the link has expired and someone tries to play/seek, and then in the handler...
store the current time of the video
send an ajax request to my server to get an updated signed URL
update the source of the player
set the current time of the video to the previously stored time
it's kind of slow/clunky, but it's the best fix i could come up with at the moment, aside from loading the entire video before allowing playback (which didn't seem like great UX).
update: this does work with videojs...but it doesn't work with either player in Safari, which apparently doesn't send the error event at all.
I'm currently rendering a list of HTML5 video elements.
I have multiple video files on a single page, i do not want to download a lot of data until the user clicks play.
I would like to grab frame 1 and show it as the poster. I dont have access to an alternative posters for each video.
I'm looking at the preload attribute with a value of 'metadata' for the video element here:
http://www.w3schools.com/tags/att_video_preload.asp
This looks to have limited browser support.
Using preload='metadata' works in firefox and chrome and show frame 1 as a poster.
Using preload='metadata' disables preloading in safari, but disabled the poster.
I have been unable to test in IE.
How do i show the HTML5 video elements frame 1 as a poster, in safari, without preloading a large chunk of data.
<video controls preload='metadata'>
<source src="{{video.url | trusted}}" type="video/mp4">
Your browser does not support the video tag.
</video>
Version v42 and above now seem to respect this. Yay!
(current beta version as of yesterday - so not yet available)
You can see now a 206 partial content request, and 66kb downloaded (my video is 600kb+)
However: VERY IMPORTANT
In case you didn't know, Chrome can only have 6 simultaneous connections at the same time to the same server.
Currently in v42 + v43 they have a terrible bug which means that once the metadata is loaded that file is not released back into the 'pool' for available connections. So if you load 6 or more videos the 7th blocks and won't download.
I've reported this as a bug https://code.google.com/p/chromium/issues/detail?id=468930
This may not be the case for all videos, but I have 10 short MP4 videos encoded with Adobe Media Encoder and they get stuck.
If in doubt, or experiencing this problem you've got no choice but to set preload='auto' for now. Hopefully this bug will never make it into the wild.