Is there a way to force a high quality THUMBNAIL for YouTube?
My videos are of very high quality and once they start streaming they run fine in 720p, however the thumbnail for the video is of variable quality - sometimes it's high, other times it's really blurry.
Is there a way of forcing a high quality thumbnail? I've found this in the API docs - http://code.google.com/apis/youtube/2.0/reference.html#youtube%5Fdata%5Fapi%5Ftag%5Fmedia:thumbnail but it doesn't detail how to use the media tag.
There is a "maxres" version as well, which is a "full hd" picture in case that the video resolution is high enough.
http://i.ytimg.com/vi/VIDEO_ID/maxresdefault.jpg
However, if the video resolution isn't high enough, this image doesn't seem to be created. So you might want to have a function that shows a lower quality version in case the "maxres" version doesn't exist.
Check out How do I get a YouTube video thumbnail from the YouTube API? for more info.
Thanks, Johan for answer.
http://i.ytimg.com/vi/VIDEO_ID/maxresdefault.jpg
If you also want set playback to HQ use Javascript API
https://developers.google.com/youtube/js_api_reference?hl=fi-FI#Playback_quality
var qualityLevels = self.players[iframeID].getAvailableQualityLevels();
/* Set highest quality */
self.players[iframeID].setPlaybackQuality(qualityLevels[0]);
In order for this to work we first need to call:
self.players[iframeID].playVideo();
Then it will triggrer
self.players[iframeID] = new YT.Player(iframeID, {
events: {
'onReady': function(event) {
var iframe = $(event.target.getIframe());
self.players[iframe.attr('id')].loaded = true;
},
'onStateChange': function(event) {
var iframe = $(event.target.getIframe());
var iframeID = iframe.attr('id');
if(event.data == 1) /* playing */
{
var qualityLevels = self.players[iframeID].getAvailableQualityLevels();
if(self.players[iframeID].getPlaybackQuality() != qualityLevels[0])
{
/* Set highest quality */
self.players[iframeID].setPlaybackQuality(qualityLevels[0]);
}
}
}
}
});
Example:
http://img.youtube.com/vi/xjFouf6j81g/hqdefault.jpg
where xjFouf6j81g, videoid
As far as I know, YouTube only offers 4 thumbnails:
http://i.ytimg.com/vi/VIDEO_ID/default.jpg
http://i.ytimg.com/vi/VIDEO_ID/1.jpg
http://i.ytimg.com/vi/VIDEO_ID/2.jpg
http://i.ytimg.com/vi/VIDEO_ID/3.jpg
The thumbnails are generated once after the upload, so you can't alter the size of them in any way.
Edit:
YouTube JS API lets you force the quality of the video, but I don't know if it will affect the video preview. See the docs for more info.
Issue has been reported here:
https://code.google.com/p/gdata-issues/issues/detail?can=2&start=0&num=100&q=&colspec=API%20ID%20Type%20Status%20Priority%20Stars%20Summary&groupby=&sort=&id=4590
Not a fix or a workaround, but if you want to avoid getting the low-res thumbnail your player should be larger than 430px wide.
So a suggested minimum size for perfect 16:9 aspect would be 432 x 243 pixels and this should get a nice-looking thumbnail.
Related
I have video's I'm streaming from Azure Media Services and are being rendered in my web page using Azure Media Player API.
I don't know ahead of time what the videos dimensions are (and they will vary). My issue is that when I play the video there is a black border (either at top/bottom or at left/right) around the video if I don't create the video element with the correct ratio to match the video. See for example the image below, notice the large black borders on the left and right of the video. I'd like to get the video size so I can correct the dimensions and get rid of the border.
The Azure Media Player API seems to say I can get the videoWidth and videoHeight. But I'm not sure (in Javascript) what object to get those values from.
In my script below, when I console.log the player object I don't see videoWidth or videoHeight as part of the player object.
let myOptions = {
controls: true,
autoplay: true,
logo: { enabled: false }
};
myPlayer = amp(video, myOptions, () => {
console.log(myPlayer);
});
myPlayer.src([{
src: "<manifestURL>",
type: "<type>"
}]);
The following screenshot is what gets logged. Unless I'm missing something, I don't see the videoWidth or videoHeight values.
Any assistance is greatly appreciated.
Actually videoWidth/videoHeight are functions.
Also you should use the this keyword inside the ready handler.
For example :
amp(video, options, () => console.log(this.videoWidth())
I am working on an academic project in which I am making a PHP project that is similar to a website https://promo.com/. This website edit videos by embedding overlay text effects on them. I made a website in which there is an overlay canvas section over the video section and I can take screenshots of canvas animation on video and then these screenshots of "Text animation" are merged as a gif and then I combine the gif and video (all this is done by FFmpeg);and the final product is a video having an overlay text animation. I take screenshots by using the code :
var canvas = document.getElementById("canvas");
var png = canvas.toDataURL("image/png");
But if the video size is 10 mins long then I have to wait for almost 10 mins so that this code in setInterval can take screenshots after every 50ms. Is that there is some library to accomplish this screenshot taking task of canvas animation so that the screenshots of text animation can be captured without playing them from start to end? I don't know what trick the promo.com website is using to record overlay text on video!
I want that I can record canvas animation as array of images without playing the whole canvas animation. Please help me in this. Thanks in advance.
Instead of first creating a canvas and then extracting images from it, You should use the video element directly. I am saying this because seeking from canvas is not in your hand, but seeking from video is. Use javascript along with setinterval both to seek the video forward 50 milisecond and capture the video's thumbnail in each milisecond, this just reduced your time by 5000 times! Here is an example:
// global or parent scope of handlers
var video = document.getElementById("video"); // added for clarity: this is needed
var i = 0;
video.addEventListener('loadeddata', function() {
this.currentTime = i;
});
video.addEventListener('seeked', function() {
// now video has seeked and current frames will show
// at the time as we expect
generateThumbnail(i);
// when frame is captured, increase here by 5 seconds
i += 5;
// if we are not past end, seek to next interval
if (i <= this.duration) {
// this will trigger another seeked event
this.currentTime = i;
}
else {
// Done!, next action
}
});
Otherwise, if it is absolutely necessary to add a canvas before, then you should create another video tag with the same source link, and hide it using css. Then you will create a javascript function which will seek it to every 5th second programmatically and keep saving the thumbnails and adding them in your container. This way, your thumbnails will be generated for the whole video without loading the whole video.
In my web app I obtain a MediaStream either via getUserMedia or getDisplayMedia. In certain situations, the video track of that stream can change its size. For example, if getDisplayMedia tracks a specific window, that window can change size. Or on a mobile device, when switching from landscape into portrait mode, the camera image will be rotated by 90° (i.e. width and height get swapped).
I know how to get the dimensions of the MediaStream (as described here). I now want to get notified whenever the dimensions change. A callback/event of some sorts.
I already tried MediaStream.onaddtrack (guessing that maybe the track is removed and readded with a different size) and I also tried using a MutationObserver on the <video> element I am showing the stream in. None of these worked. I also checked MDN for other events that might help me, but I didn't find any promising ones.
Is there a way to subscribe to changes of a video track's dimension? A function of mine should be called each time the dimensions change. And if it's not possible and I would need to busy poll: is there a smart way how to make the polling a bit less busy?
You can subscribe to resize event of your video element
const video = document.getElementById("video");
video.addEventListener("resize", (e) => {
const { videoWidth, videoHeight } = video;
// can do smth here
// for example
video.style.width = videoWidth;
video.style.height = videoHeight;
}, false);
I am scratching my head over inconsistencies on youtube embeds playback quality on mobile devices.
I am using the iframe api and I have created a demo to showcase the code:
https://ancientoffbeatrotation--five-nine.repl.co/
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<script src="index.js"></script>
<iframe id="ytplayer" type="text/html" style="position:absolute; top:0px; left:0px; bottom:0px; right:10px; border:none; margin:0; padding:0; overflow:hidden; z-index:999999;" src="https://www.youtube-nocookie.com/embed/_r3LynEZuko?playlist=_r3LynEZuko&rel=0&autoplay=1&playsinline=1&controls=0&showinfo=0&enablejsapi=1" frameborder="0" allowfullscreen></iframe>
</body>
</html>
JS
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('ytplayer', {
events: {
'onReady': onPlayerReady,
'onPlaybackQualityChange': onPlayerPlaybackQualityChange,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady() {
player.playVideo();
player.mute();
}
function onPlayerPlaybackQualityChange(event) {
var available_qualities = player.getAvailableQualityLevels();
alert("Available qualities are" + available_qualities);
var displayed_quality= player.getPlaybackQuality();
alert("Used quality is" + displayed_quality);
}
function onPlayerStateChange(event) {
if(event.data === YT.PlayerState.PLAYING){
event.target.setSize( width=7000, height=10000 ); //huge dimensions
}
}
Note: I used repl.it instead of jsfiddle or codenpen because the two latter use iframes so it tampares/modifies the pixels available for the youtube iframe which can make our observations wrong. Instead, repl.it does not use any iframe and deploys a real html page so we can trust it more for this experiments.
In theory
Youtube says it will use the height of the video to set the resolution (even if it can change it based on other factors it can alone decide like speed of connection...):
The list below shows the playback quality levels that correspond to
different standard player sizes. We recommend that you set the height
of your video player to one of the values listed below and that you
size your player to use 16:9 aspect ratio.
As stated above, even if
you choose a standard player size, we also recommend that you set the
suggestedQuality parameter value to default to enable YouTube to
select the most appropriate playback quality.
small: Player height is
240px, and player dimensions are at least 320px by 240px for 4:3
aspect ratio. medium: Player height is 360px, and player dimensions
are 640px by 360px (for 16:9 aspect ratio) or 480px by 360px (for 4:3
aspect ratio).
large: Player height is 480px, and player dimensions
are 853px by 480px (for 16:9 aspect ratio) or 640px by 480px (for 4:3
aspect ratio).
hd720: Player height is 720px, and player dimensions
are 1280px by 720px (for 16:9 aspect ratio) or 960px by 720px (for 4:3
aspect ratio).
hd1080: Player height is 1080px, and player dimensions
are 1920px by 1080px (for 16:9 aspect ratio) or 1440px by 1080px (for
4:3 aspect ratio).
highres: Player height is greater than 1080px,
which means that the player's aspect ratio is greater than 1920px by
1080px. default: YouTube selects the appropriate playback quality.
This setting effectively reverts the quality level to the default
state and nullifies any previous efforts to set playback quality using
the cueVideoById, loadVideoById or setPlaybackQuality functions.
I insist on the fact I am not using in the demo code the method setPlaybackquality which has not been working at all for the past few months, even if it is still undocumented ( see here, or here), so this is not about I think the issue of the method setPlaybackQuality.
In practice: The gist of the bug
I am just setting the size with setSize() and youtube is accordingly changing the video resolution. And I observe that changing it does on a desktop perfectly works according to this table given by google. but on mobile it's like it works...until a certain point, it's like there is a "ceiling", a resolution which is the maximum allowed by Youtube, based on unknown and very odd (see my experiments further below) criteria to me, which is capping the resolution that can be set. On my iphone 7 it's always capped at "HD720". On my Huawei Android P SMart it's always capped at "Large". So I don't get it: I mean on a super fast wifi at home even I can't get for huge dimensions of the demo video (height >5000px) hd 1080 and I am always maxed at hd720.
Here is a demo to share my findings so far: https://ancientoffbeatrotation--five-nine.repl.co/
Note that all tests are performed on a very recent chrome (>=64); safari on ios behaves the same way in my experiments.
on a chrome large desktop display window of 1800 x 945, I get a youtube video with a resolution of hd 1080 (highest available cool): perfect, as expected
chrome dev tools > emulate iphone7 so it takes dimensions of 375px x 667px => 1080hd is used, perfect, as expected
then on a real iphone 7 or browserstack (service to use real devices on the cloud): here the resolution used is hd720 despite the huge vidoe dimensions that should ensure it loads in hd1080. Right here is the issue.
Context: very good wifi connection, full batteries (no low battery mode that could add constraint on rich media download)
Same issue with my android phone where it does not even make it to hd720 and is set to "large".
Another "fascinating" observation is : I decided to add in the code an alert to know which so that which quality is available, the mystery deepens
function onPlayerPlaybackQualityChange(event) {
var available_qualities = player.getAvailableQualityLevels();
alert("Available qualities are" + available_qualities);
}
And the mystery clarifies but re-depeens again :( as shown below:
on desktop: I read for this alert "available qualities are: hd1080, hd720,large, medium, tiny, auto"
=> so in the observations above, I got indeed the highest possible quality, which is fine given the video dimensions
on the real iphone 7: I read for this alert "available qualities are: hd720, medium, small, auto"
So I thought, haha that's why I am getting hd720 maybe as it's the maximum availmable. But why? my connection speed i super strong and my phone pretty modern (iphone 7).
but the mystery deepens because with the above observation on iphone 7, I thought "ok at least I understand a little bit more now, I got the highest resolution available, it's just that hd720 was the maximum available for some reason", but the mystery deepens when I test on my huawei P Smart : here I read on the alert "available qualities are: hd1080, hd720, large, mediom, small, tiny, auto" so I would expect to get the highest hd1080 resolution...but no I am getting ..."large" (not even hd720!). So my theory goes down. Plus why on earth would iphone 7 get in available qualities hd720 as highest resolution and huawei P Smart hd1080 (note: when I checked the screen resolution of the phone it said: 2160 x 1080)
I thought maybe like some people mentioned in the press, my internet operator (free mobile in France) is doing the same throttling a verizon or t-mobile in the US for youtube, but I tried with various proxies in the world and observations are always the same. so the issue is likely not related to this.
I'm a super lost here, anybody has an idea what's going on ?
Im in the process of developing a 'flipbook-style' animation using Skrollr by triggering background image changes when the user scrolls to indicated positions on the page. The issue i'm having is that in browser the image changes are delayed, creating what can only be defined as a 'flicker' of white between the frames.
<div class="section" style="background: url('frame1.png')"
data-560-top="background-image:!url('frame1.png');"
data-440-top="background-image:!url('frame2.png');">
The HTML is simple; it basically states that at 560 pixels from the top of the div (in relation to the browser window), the background should be at frame 1, then as the user scrolls closer to the div (440 pixels from the top of the div) the background image changes to frame 2. I plan to use up to around 20 frames and the images are quite large.
I have created a JSBin here which includes a very simplified sample with images from placehold.it. This includes the Skrollr script and an example layout of a section of my project. The key difference being that the images in my project are of much larger scale.
(function($) {
var cache = [];
// Arguments are image paths relative to the current page.
$.preLoadImages = function() {
var args_len = arguments.length;
for (var i = args_len; i--;) {
var cacheImage = document.createElement('img');
cacheImage.src = arguments[i];
cache.push(cacheImage);
}
};
})(jQuery);
jQuery.preLoadImages(
'http://www.placehold.it/300x200.png',
'http://www.placehold.it/300x200.png'
);
The above snippet seems to be working on Chrome, however the flicker issue remains in Firefox. Based on research, firefox handles cached images differently from Chrome? (e.g Where an image is not considered needed by firefox at a given time, it is trashed?)
I would like to know how I could possibly force all browsers to preload the images efficiently, to potentially avoid the background image flicker upon change. I am still quite new to Javascript/JQuery.
I hope I have provided a clear explanation. All assistance appreciated.
Dan
You can preload images using CSS only, no need for JS. Check out this article for more info. Another interesting way to do it is in the comment section of the article. Basically you assign the background image to a pseudo-element so that is is cached and ready to be used whenever. See this code for an example:
#something:before {
content: url("./img.jpg");
width:0;
height:0;
visibility:hidden;
}