Kaynakları etkin bir şekilde önceden yükleyerek medya oynatma işlemlerinizi nasıl hızlandırabilirsiniz?
Oynatmanın daha hızlı başlatılması videonuzu izleyen veya dinleyen daha fazla kişinin olacağı anlamına gelir. ses'e dokunun. Bu bilinen bir gerçek. Bu makalede, ses ve video oynatmanızı hızlandırmak için kullanabileceğiniz teknikler kullanım alanınıza bağlı olarak kaynakları önceden yükleme.
Medya dosyalarını önceden yüklemenin üç yöntemini anlatacağım. İlk olarak bir profesyonelden bahsedeceğim. ve dezavantajları.
Harika... | Ama... | |
---|---|---|
Video önceden yükleme özelliği | Web sunucusunda barındırılan benzersiz bir dosya için kullanımı basittir. | Tarayıcılar bu özelliği tamamen yoksayabilir. |
Kaynak getirme işlemi, HTML belgesi tamamen yüklendiğinde ve ayrıştırılır. | ||
Medya Kaynağı Uzantıları (MSE), medya öğelerinde preload özelliğini yoksayar
MSE'ye medya içeriği sağlıyor.
|
||
Bağlantı önceden yükleme |
Tarayıcıyı engellemeden bir video kaynağı için istekte bulunmaya zorlar.
dokümanın onload etkinliği.
|
HTTP Aralığı istekleri uyumlu değildir. |
MSE ve dosya segmentleriyle uyumludur. | Tam kaynaklar alınırken yalnızca küçük medya dosyaları (5 MB'tan küçük) için kullanılmalıdır. | |
Manuel arabelleğe alma | Tam kontrol | Karmaşık hataların ele alınması web sitesinin sorumluluğundadır. |
Videonun önceden yüklenmesi özelliği
Video kaynağı, web sunucusunda barındırılan benzersiz bir dosyaysa
video preload
özelliğini kullanarak tarayıcıya nasıl
fazla bilgi veya içerik olmasına dikkat edin. Bu, Medya Kaynağı Uzantılarının
(MSE), preload
ile uyumlu değildir.
Kaynak getirme işlemi, yalnızca ilk HTML belgesi hazır olduğunda
tamamen yüklendi ve ayrıştırıldı (ör. DOMContentLoaded
etkinliği tetiklendi)
Diğer yandan, kaynak olduğunda çok farklı load
etkinliği tetiklenir
getirildiğinden emin olun.
preload
özelliğinin metadata
olarak ayarlanması, kullanıcının
olması beklenen ancak videonun meta verilerini (boyutlar, parça
(ör. liste, süre vb.) kullanılabilir. Chrome'dan başlayarak
64, preload
için varsayılan değer metadata
şeklindedir. (Tarih: auto
).
<video id="video" preload="metadata" src="file.mp4" controls></video>
<script>
video.addEventListener('loadedmetadata', function() {
if (video.buffered.length === 0) return;
const bufferedSeconds = video.buffered.end(0) - video.buffered.start(0);
console.log(`${bufferedSeconds} seconds of video are ready to play.`);
});
</script>
preload
özelliğinin auto
olarak ayarlanması, tarayıcının önbelleğe alabileceğini gösterir
ve oynatmanın durdurulmasına gerek kalmadan tamamlanabilmesi için yeterli veri
arabelleğe alma.
<video id="video" preload="auto" src="file.mp4" controls></video>
<script>
video.addEventListener('loadedmetadata', function() {
if (video.buffered.length === 0) return;
const bufferedSeconds = video.buffered.end(0) - video.buffered.start(0);
console.log(`${bufferedSeconds} seconds of video are ready to play.`);
});
</script>
Yine de bazı uyarılar var. Bu sadece bir ipucu olduğu için, tarayıcı
preload
özelliğini yoksayın. Bu yazının hazırlandığı sırada bazı kurallar
Chrome'da uygulandı:
- Veri Tasarrufu etkinleştirildiğinde Chrome,
preload
değerininone
. - Android 4.3'te Chrome, Android 4.0 sürümü nedeniyle
preload
değerininone
olarak zorunlu kılar Hata. - Hücresel bağlantılarda (2G, 3G ve 4G), Chrome
preload
değerinimetadata
.
İpuçları
Web siteniz aynı alanda birçok video kaynağı içeriyorsa
preload
değerini metadata
olarak ayarlamanızı veya poster
değerini tanımlamanızı öneririz.
özelliğini kullanarak preload
özelliğini none
olarak ayarlayın. Bu şekilde, ilgili riskleri
aynı alan adına yönelik maksimum HTTP bağlantısı sayısı (sırasına göre 6
HTTP 1.1 spesifikasyonu). Bu işlemin
Videolar temel kullanıcı deneyiminizin bir parçası değilse sayfa hızını artırabilirsiniz.
Bağlantı önceden yükleme
Diğer makalelerde incelendiği üzere bağlantı önceden yükleme, bildirime dayalı bir getirme işlemidir.
tarayıcı, herhangi bir bağlantı olmadan bir kaynak için istekte bulunmaya zorlamanıza
load
etkinliğini engelliyor ve sayfa indirilirken. Kaynaklar
<link rel="preload">
aracılığıyla yüklenen kaynaklar tarayıcıda yerel olarak depolanır
DOM, JavaScript veya İYS'de açıkça referans verilene kadar
kullanabilirsiniz.
Önceden yükleme, geçerli gezinmeye ve yoğunluğa odaklanması açısından kaynakları türlerine (komut dosyası, stil, yazı tipi, video, ses vb.). Tarayıcı önbelleğini, mevcut sunucu önbelleğine anlamına gelir.
Videonun tamamını önceden yükle
Videonun tamamındaki içerikleri web sitenize önceden yükleyerek JavaScript video içeriğinin getirilmesini istiyor, kaynak olarak önbellekten okunur tarayıcı tarafından önceden önbelleğe alınmış olabilir. Önceden yükleme isteği normal bir ağ getirmesi gerçekleşir.
<link rel="preload" as="video" href="https://cdn.com/small-file.mp4">
<video id="video" controls></video>
<script>
// Later on, after some condition has been met, set video source to the
// preloaded video URL.
video.src = 'https://cdn.com/small-file.mp4';
video.play().then(() => {
// If preloaded video URL was already cached, playback started immediately.
});
</script>
Çünkü önceden yüklenmiş kaynak, bir video öğesi tarafından
örnekte, as
ön yükleme bağlantısının değeri video
şeklindedir. Sesli olsaydı
öğesi, as="audio"
olacaktır.
İlk segmenti önceden yükle
Aşağıdaki örnekte, bir videonun ilk segmentinin <link
rel="preload">
ile nasıl önceden yükleneceği ve Medya Kaynağı Uzantıları ile nasıl kullanılacağı gösterilmektedir. Bilmiyorsanız
MSE JavaScript API ile MSE ile ilgili temel bilgileri inceleyin.
Basitlik açısından, tüm videonun bölündüğünü ve
file_1.webm
, file_2.webm
, file_3.webm
vb. daha küçük dosyalar
<link rel="preload" as="fetch" href="https://cdn.com/file_1.webm">
<video id="video" controls></video>
<script>
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen, { once: true });
function sourceOpen() {
URL.revokeObjectURL(video.src);
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp09.00.10.08"');
// If video is preloaded already, fetch will return immediately a response
// from the browser cache (memory cache). Otherwise, it will perform a
// regular network fetch.
fetch('https://cdn.com/file_1.webm')
.then(response => response.arrayBuffer())
.then(data => {
// Append the data into the new sourceBuffer.
sourceBuffer.appendBuffer(data);
// TODO: Fetch file_2.webm when user starts playing video.
})
.catch(error => {
// TODO: Show "Video is not available" message to user.
});
}
</script>
Destek
Şu parametreyle <link rel=preload>
için çeşitli as
türlerinin desteklendiğini tespit edebilirsiniz:
aşağıdaki snippet'leri içerir:
function preloadFullVideoSupported() {
const link = document.createElement('link');
link.as = 'video';
return (link.as === 'video');
}
function preloadFirstSegmentSupported() {
const link = document.createElement('link');
link.as = 'fetch';
return (link.as === 'fetch');
}
Manuel arabelleğe alma
Cache API'ye ve hizmet çalışanlarına geçmeden önce
MSE ile bir videonun manuel olarak nasıl arabelleğe alınacağına. Aşağıdaki örnekte, web sitenizin
sunucu HTTP'yi destekliyor Range
olacaktır, ancak bu, dosya içine benzer ve
emin olun. Google'ın Shaka'sı gibi bazı ara katman yazılımı kitaplıkları
Player, JW Player ve Video.js
sizin için hazırlandı.
<video id="video" controls></video>
<script>
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen, { once: true });
function sourceOpen() {
URL.revokeObjectURL(video.src);
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp09.00.10.08"');
// Fetch beginning of the video by setting the Range HTTP request header.
fetch('file.webm', { headers: { range: 'bytes=0-567139' } })
.then(response => response.arrayBuffer())
.then(data => {
sourceBuffer.appendBuffer(data);
sourceBuffer.addEventListener('updateend', updateEnd, { once: true });
});
}
function updateEnd() {
// Video is now ready to play!
const bufferedSeconds = video.buffered.end(0) - video.buffered.start(0);
console.log(`${bufferedSeconds} seconds of video are ready to play.`);
// Fetch the next segment of video when user starts playing the video.
video.addEventListener('playing', fetchNextSegment, { once: true });
}
function fetchNextSegment() {
fetch('file.webm', { headers: { range: 'bytes=567140-1196488' } })
.then(response => response.arrayBuffer())
.then(data => {
const sourceBuffer = mediaSource.sourceBuffers[0];
sourceBuffer.appendBuffer(data);
// TODO: Fetch further segment and append it.
});
}
</script>
Dikkat edilmesi gereken noktalar
Medya arabelleğe alma deneyiminin tamamının kontrolü artık sizde olduğundan, cihazın pil seviyesini, "Veri Tasarrufu Modu"nu kullanıcının tercihi ve ağ bilgilerini kullanabilirsiniz.
Pil farkındalığı
Kullanıcıların pil seviyesini dikkate alın hangi cihazları tercih edeceğimizi videoları önceden yükleme hakkındadır. Güç seviyesi devre dışı bırakıldığında pil ömrünü korur. düşük.
Şu durumlarda önceden yüklemeyi devre dışı bırakın veya en azından daha düşük çözünürlüklü bir videoyu önceden yükleyin: cihazın pili bitmek üzere.
if ('getBattery' in navigator) {
navigator.getBattery()
.then(battery => {
// If battery is charging or battery level is high enough
if (battery.charging || battery.level > 0.15) {
// TODO: Preload the first segment of a video.
}
});
}
"Veri Tasarrufu"nu algılama
Hızlı ve hafif içerik yayınlamak için Save-Data
istemci ipucu isteği başlığını kullanın
"veri tasarrufu" özelliğini etkinleştiren kullanıcılara yönelik uygulamalar kendi modlarında
emin olun. Bu istek başlığını tanımlayarak, uygulamanız
Maliyet ve performans kısıtlamalı bir şekilde optimize edilmiş bir kullanıcı deneyimi sunun
yardımcı olur.
Daha fazla bilgi edinmek için Save-Data ile Hızlı ve Hafif Uygulamalar Yayınlama bölümüne bakın.
Ağ bilgilerine dayalı akıllı yükleme
Önceden yükleme işleminden önce navigator.connection.type
sayfasını kontrol etmenizi öneririz. Zaman
cellular
olarak ayarlanırsa önceden yüklemeyi engelleyebilir ve kullanıcılara
mobil şebeke operatörü, bant genişliği için şarj ediyor olabilir ve
önceden önbelleğe alınmış içeriğin otomatik olarak oynatılması.
if ('connection' in navigator) {
if (navigator.connection.type == 'cellular') {
// TODO: Prompt user before preloading video
} else {
// TODO: Preload the first segment of a video.
}
}
Ağa nasıl tepki vereceğinizi öğrenmek için Ağ Bilgileri örneğine göz atın kabullenmek de önemlidir.
Birden çok ilk segmenti önbelleğe al
Şimdi, bir sürü medya içeriği olmadan
spekülatif olarak önceden yüklemek
kullanıcının en sonunda hangi medyayı seçeceğini biliyor musunuz? Kullanıcı bir
web sayfasını ziyaret ederseniz muhtemelen o videoyu getirmeye yetecek kadar belleğimiz vardır.
segment dosyası oluşturacağız, ancak kesinlikle 10 gizli <video>
oluşturmamalıyız
öğeleri ve 10 MediaSource
nesne oluşturur ve bu verileri yayınlamaya başlar.
Aşağıdaki iki bölümden oluşan örnekte, GCLID'nin birden fazla ilk segmentini önbelleğe almanın
güçlü ve kullanımı kolay Cache API'den yararlanarak video ile ilgili daha fazla bilgi edinebilirsiniz. Benzer bir şeyin
IndexedDB ile de elde edilebilir. Henüz Service Worker'ları kullanmıyoruz.
Cache API'ye window
nesnesinden de erişilebilir.
Getirme ve önbelleğe alma
const videoFileUrls = [
'bat_video_file_1.webm',
'cow_video_file_1.webm',
'dog_video_file_1.webm',
'fox_video_file_1.webm',
];
// Let's create a video pre-cache and store all first segments of videos inside.
window.caches.open('video-pre-cache')
.then(cache => Promise.all(videoFileUrls.map(videoFileUrl => fetchAndCache(videoFileUrl, cache))));
function fetchAndCache(videoFileUrl, cache) {
// Check first if video is in the cache.
return cache.match(videoFileUrl)
.then(cacheResponse => {
// Let's return cached response if video is already in the cache.
if (cacheResponse) {
return cacheResponse;
}
// Otherwise, fetch the video from the network.
return fetch(videoFileUrl)
.then(networkResponse => {
// Add the response to the cache and return network response in parallel.
cache.put(videoFileUrl, networkResponse.clone());
return networkResponse;
});
});
}
HTTP Range
istekleri kullanırsam manuel olarak yeniden oluşturmam gerekeceğini unutmayın.
Önbellek API'si Range
yanıtlarını henüz desteklemediğinden bir Response
nesnesi.
networkResponse.arrayBuffer()
çağrısının tüm içeriği getireceğine dikkat edin
oluşturmak için kullanılabilir. Bu nedenle, birden fazla
fark edebilirsiniz.
Referans olması amacıyla, yukarıdaki örneğin bir bölümünü HTTP Aralığını kaydedecek şekilde değiştirdim video önbelleğine aktarmanızı sağlar.
...
return fetch(videoFileUrl, { headers: { range: 'bytes=0-567139' } })
.then(networkResponse => networkResponse.arrayBuffer())
.then(data => {
const response = new Response(data);
// Add the response to the cache and return network response in parallel.
cache.put(videoFileUrl, response.clone());
return response;
});
Videoyu oynat
Kullanıcı oynat düğmesini tıkladığında videonun ilk segmentini alırız Cache API'sinde mevcut, böylece oynatma varsa hemen başlar. Aksi takdirde, dosyayı ağdan alırız. Tarayıcıların Kullanıcılar Önbelleği temizlemeye karar verebilir.
Daha önce gördüğümüz gibi, MSE'yi kullanarak videonun ilk segmentini videoya aktarıyoruz. öğesine dokunun.
function onPlayButtonClick(videoFileUrl) {
video.load(); // Used to be able to play video later.
window.caches.open('video-pre-cache')
.then(cache => fetchAndCache(videoFileUrl, cache)) // Defined above.
.then(response => response.arrayBuffer())
.then(data => {
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen, { once: true });
function sourceOpen() {
URL.revokeObjectURL(video.src);
const sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp09.00.10.08"');
sourceBuffer.appendBuffer(data);
video.play().then(() => {
// TODO: Fetch the rest of the video when user starts playing video.
});
}
});
}
Hizmet çalışanı ile aralık yanıtları oluşturma
Peki bir video dosyasının tamamını getirip
var mı? Tarayıcı bir HTTP Range
isteği gönderdiğinde
Cache API'si çalışmadığı için videonun tamamını oluşturucu belleğine taşımak istiyorsanız
Range
yanıtları henüz desteklenmektedir.
Şimdi, bu isteklere nasıl müdahale edeceğimi ve özelleştirilmiş bir Range
döndüreceğimi göstereyim
yanıt vermesi gerekir.
addEventListener('fetch', event => {
event.respondWith(loadFromCacheOrFetch(event.request));
});
function loadFromCacheOrFetch(request) {
// Search through all available caches for this request.
return caches.match(request)
.then(response => {
// Fetch from network if it's not already in the cache.
if (!response) {
return fetch(request);
// Note that we may want to add the response to the cache and return
// network response in parallel as well.
}
// Browser sends a HTTP Range request. Let's provide one reconstructed
// manually from the cache.
if (request.headers.has('range')) {
return response.blob()
.then(data => {
// Get start position from Range request header.
const pos = Number(/^bytes\=(\d+)\-/g.exec(request.headers.get('range'))[1]);
const options = {
status: 206,
statusText: 'Partial Content',
headers: response.headers
}
const slicedResponse = new Response(data.slice(pos), options);
slicedResponse.setHeaders('Content-Range': 'bytes ' + pos + '-' +
(data.size - 1) + '/' + data.size);
slicedResponse.setHeaders('X-From-Cache': 'true');
return slicedResponse;
});
}
return response;
}
}
Bu dilimlenmiş dosyayı yeniden oluşturmak için response.blob()
kullandığımı unutmamak önemlidir.
yanıtı verdiğinden, bu işlem bana dosyayı
response.arrayBuffer()
, tüm dosyayı oluşturucu belleğine getirir.
Özel X-From-Cache
HTTP başlığım, bu isteğin olup olmadığını öğrenmek için kullanılabilir
veya ağdan geldiğini öğrenebilirsiniz. Şu gibi oyuncular tarafından kullanılabilir:
ShakaPlayer'ın kontrol ederek yanıt süresini
ağ hızı.
Resmi Sample Media App'i, özellikle de uygulamayı
Range
ile ilgili eksiksiz bir çözüm için ranged-response.js dosyasını kullanabilirsiniz.
kabul edersiniz.