zmiana źródła na tag wideo html5


138

Próbuję zbudować odtwarzacz wideo, który działa wszędzie. do tej pory chciałbym:

<video>
    <source src="video.mp4"></source>
    <source src="video.ogv"></source>
    <object data="flowplayer.swf" type="application/x-shockwave-flash">
        <param name="movie" value="flowplayer.swf" />
        <param name="flashvars" value='config={"clip":"video.mp4"}' />
    </object>
</video>

(jak widać na kilku stronach, na przykład wideo dla wszystkich ), tak dobrze.

ale teraz chcę też jakąś listę odtwarzania / menu wraz z odtwarzaczem wideo, z którego mogę wybierać inne filmy. powinny one zostać natychmiast otwarte w moim odtwarzaczu. więc będę musiał „dynamicznie zmieniać źródło wideo” (jak widać na dev.opera.com/articles/everything-you-need-to-know-html5-video-audio/ - sekcja „Spójrzmy na inny film ”) za pomocą javascript. zapomnijmy na razie o części flashplayera (a tym samym IE), spróbuję się tym zająć później.

więc mój JS do zmiany <source>tagów powinien wyglądać mniej więcej tak:

<script>
function loadAnotherVideo() {
    var video = document.getElementsByTagName('video')[0];
    var sources = video.getElementsByTagName('source');
    sources[0].src = 'video2.mp4';
    sources[1].src = 'video2.ogv';
    video.load();
}
</script>

Problem polega na tym, że to nie działa we wszystkich przeglądarkach. a mianowicie firefox = O jest fajna strona, na której możesz obserwować problem, który mam: http://www.w3.org/2010/05/video/mediaevents.html

gdy tylko uruchomię metodę load () (pamiętaj, że w przeglądarce Firefox) odtwarzacz wideo umiera.

teraz dowiedziałem się, że kiedy nie używam wielu <source>tagów, a zamiast tego tylko jeden atrybut src w <video>tagu, całość DZIAŁA w przeglądarce Firefox.

więc planuję po prostu użyć tego atrybutu src i określić odpowiedni plik za pomocą funkcji canPlayType () .

czy robię to źle, czy też komplikuję sprawę?


Dla mnie to brzmi dobrze. Jak to jest „skomplikowane”, aby uprościć znaczniki?
Matt Ball

problem polega na tym, że widzę dużo javascript i rozróżnianie przypadków. jeśli może coś przeoczyłem, na przykład był sposób, aby działało w przeglądarce Firefox z wieloma <source>tagami. to przypuszczam, że byłoby łatwiej
sashn

czy kiedykolwiek zastanawiałeś się nad częścią flash na ie8?
Neeraj

@Neeraj, ostateczne rozwiązanie obejmowało wtyczkę video.js, która używa Flash Playera jako rozwiązania zastępczego dla IE8 i podobnych. Jednak dzisiaj mogą istnieć lepsze wtyczki. użycie wtyczki również nie pomogło w problemie z firefoxem dotyczącym metody load (), która była początkową motywacją dla tego postu. wydaje się, że dzisiaj ten problem został już rozwiązany.
sashn

Odpowiedzi:


169

Nienawidziłem tych wszystkich odpowiedzi, ponieważ były zbyt krótkie lub opierały się na innych ramach.

Oto "jeden" waniliowy sposób JS na to, działający w Chrome, prosimy o przetestowanie w innych przeglądarkach:

http://jsfiddle.net/mattdlockyer/5eCEu/2/

HTML:

<video id="video" width="320" height="240"></video>

JS:

var video = document.getElementById('video');
var source = document.createElement('source');

source.setAttribute('src', 'http://www.tools4movies.com/trailers/1012/Kill%20Bill%20Vol.3.mp4');

video.appendChild(source);
video.play();

setTimeout(function() {  
    video.pause();

    source.setAttribute('src', 'http://www.tools4movies.com/trailers/1012/Despicable%20Me%202.mp4'); 

    video.load();
    video.play();
}, 3000);

11
To był dla mnie najczystszy i najbardziej wydajny.
Phil McCarty

Nie mogłem zmusić Chrome, żeby grał z tym w piłkę. TYLKO jeśli ustawię atrybut src wideo na ścieżkę webm
Adam Hey

2
Metoda odtwarzania jest dozwolona tylko gestem użytkownika w niektórych zasadach przeglądarki.
Anson

Bardzo to doceniam z innego powodu! Próbowałem założyć stronę wideo, która nie pokazuje ŻADNEGO wideo, dopóki odwiedzający go nie wybierze. Mógłbym skonfigurować tag wideo z pustym tagiem źródłowym, ale zawsze generowałoby to błąd w konsoli debugowania javascript. Teraz wiem, że mogę wstrzymać się z dodaniem „źródła”, dopóki użytkownik go nie wybierze. Do tej pory nie rozumiałem, że muszę użyć funkcji CreateElement (), aby utworzyć źródło, a następnie użyć metody appendChild (), aby dodać ją do elementu wideo! W przypadku kolejnego wyboru mogę najpierw sprawdzić, czy element źródłowy istnieje, więc nie powtarzam tego kroku.
Randy

To rozwiązanie działa świetnie, jeśli ktoś ma problem z typem zawartości z odpowiedzi ładunku, nawet jeśli określony typ zawartości jest poprawny, ale nadal zachowuje się dziwnie.
meDeepakJain

63

Modernizr działał na mnie jak urok.

Zrobiłem to, że nie użyłem <source>. W jakiś sposób to spieprzyło sprawę, ponieważ wideo działało tylko przy pierwszym wywołaniu load (). Zamiast tego użyłem atrybutu source wewnątrz tagu wideo -> <video src="blabla.webm" />i użyłem Modernizr, aby określić, jaki format obsługuje przeglądarka.

<script>
var v = new Array();

v[0] = [
        "videos/video1.webmvp8.webm",
        "videos/video1.theora.ogv",
        "videos/video1.mp4video.mp4"
        ];
v[1] = [
        "videos/video2.webmvp8.webm",
        "videos/video2.theora.ogv",
        "videos/video2.mp4video.mp4"
        ];
v[2] = [
        "videos/video3.webmvp8.webm",
        "videos/video3.theora.ogv",
        "videos/video3.mp4video.mp4"
        ];

function changeVid(n){
    var video = document.getElementById('video');

    if(Modernizr.video && Modernizr.video.webm) {
        video.setAttribute("src", v[n][0]);
    } else if(Modernizr.video && Modernizr.video.ogg) {
        video.setAttribute("src", v[n][1]);
    } else if(Modernizr.video && Modernizr.video.h264) {
        video.setAttribute("src", v[n][2]);
    }

    video.load();
}
</script>

Mam nadzieję, że to ci pomoże :)

Jeśli nie chcesz korzystać z Modernizr , zawsze możesz użyć CanPlayType () .


Czy nie masz na myśli v [n] [1] po drugie, jeśli (Modernizr.video && Modernizr.video.ogg) jest prawdą?
bergie3000,

1
Po wypróbowaniu innych metod wypróbowałem to podejście Modernizr i zadziałało dobrze. Chrome (z jakiegoś powodu) nie załadowałby mp4 w moim przypadku, ale załadowałby webm. Dzięki @MariusEngenHaugen
Adam Hey

Cieszę się, że mogłem służyć @AdamHey
Marius Engen Haugen

32

Twój oryginalny plan brzmi dla mnie dobrze. Prawdopodobnie znajdziesz więcej dziwactw przeglądarki zajmujących się dynamicznym zarządzaniem <source>elementami, jak wskazano tutaj w uwadze specyfikacji W3:

Dynamiczna modyfikacja elementu źródłowego i jego atrybutu, gdy element jest już wstawiony do elementu wideo lub audio, nie przyniesie żadnego efektu. Aby zmienić to, co jest odtwarzane, po prostu użyj bezpośrednio atrybutu src w elemencie media, prawdopodobnie używając metody canPlayType () do wybierania spośród dostępnych zasobów. Ogólnie rzecz biorąc, ręczne manipulowanie elementami źródłowymi po przeanalizowaniu dokumentu jest niezbyt [sic] skomplikowanym podejściem.

http://dev.w3.org/html5/spec/Overview.html#the-source-element


19

Rozwiązałem to za pomocą tej prostej metody

function changeSource(url) {
   var video = document.getElementById('video');
   video.src = url;
   video.play();
}

10

Zamiast pobierać ten sam odtwarzacz wideo do ładowania nowych plików, dlaczego nie usunąć całego <video>elementu i nie odtworzyć go. Większość przeglądarek załaduje go automatycznie, jeśli src są poprawne.

Przykład (używając Prototype ):

var vid = new Element('video', { 'autoplay': 'autoplay', 'controls': 'controls' });
var src = new Element('source', { 'src': 'video.ogg', 'type': 'video/ogg' });

vid.update(src);
src.insert({ before: new Element('source', { 'src': 'video.mp4', 'type': 'video/mp4' }) });

$('container_div').update(vid);

6
To znacznie spowalnia całą przeglądarkę, ponieważ nawet po usunięciu tagu wideo przeglądarka nadal ładuje usunięte filmy do końca.
Moe Sweet

Niektóre przeglądarki (mobilne) nie pozwalają na programowe odtwarzanie multimediów bez interakcji użytkownika, a ponieważ miałeś już interakcję z elementem, zastąpienie go nowym spowoduje utratę tej zdolności.
Max Waterman

6

Po prostu umieść element DIV i zaktualizuj zawartość ...

<script>
function setvideo(src) {
    document.getElementById('div_video').innerHTML = '<video autoplay controls id="video_ctrl" style="height: 100px; width: 100px;"><source src="'+src+'" type="video/mp4"></video>';
    document.getElementById('video_ctrl').play();
}
</script>
<button onClick="setvideo('video1.mp4');">Video1</button>
<div id="div_video"> </div>

6

Zgodnie ze specyfikacją

Dynamiczna modyfikacja elementu źródłowego i jego atrybutu, gdy element jest już wstawiony do elementu wideo lub audio, nie przyniesie żadnego efektu. Aby zmienić to, co jest odtwarzane, po prostu użyj bezpośrednio atrybutu src w elemencie media, prawdopodobnie używając metody canPlayType () do wybierania spośród dostępnych zasobów. Ogólnie rzecz biorąc, ręczne manipulowanie elementami źródłowymi po przeanalizowaniu dokumentu jest niezbyt skomplikowanym podejściem.

Więc to, co próbujesz zrobić, najwyraźniej nie powinno działać.


@ greg.kindel Zauważyłem po wysłaniu ... ale powodem, dla którego nie zauważyłem w pierwszej kolejności, jest to, że tekst wprowadzający jest zagmatwany. O jakim oryginalnym planie mówimy? Oryginalny plan, który nie zadziała, czy zaktualizowany oryginalny plan zgodny z wytycznymi, które oboje opublikowaliśmy?
Yaur

w porządku, powinienem był zacytować. Miałem na myśli jego plan, aby „po prostu użyć tego atrybutu src i określić odpowiedni plik za pomocą funkcji canPlayType ()”, która działa.
greg.kindel

4

Yaur: Chociaż to, co skopiowałeś i wkleiłeś, jest dobrą radą, nie oznacza to, że nie można elegancko zmienić elementu źródłowego elementu wideo HTML5, nawet w IE9 (lub IE8 jeśli o to chodzi). (To rozwiązanie NIE obejmuje wymiana całego elementu wideo, ponieważ jest to zła praktyka kodowania).

Kompletne rozwiązanie do zmiany / przełączania filmów w tagach wideo HTML5 za pomocą javascript można znaleźć tutaj i jest testowane we wszystkich przeglądarkach HTML5 (Firefox, Chrome, Safari, IE9 itp.).

Jeśli to pomoże lub masz problemy, daj mi znać.


Znakomity! To jest sposób na zrobienie tego. Nie potrzebujesz nawet jQuery; w połączonym kodzie podstaw: mp4Vid.setAttribute ('src', "/pathTo/newVideo.mp4");
Velojet

3

Przychodzę z tym, aby dynamicznie zmieniać źródło wideo. Zdarzenie „canplay” czasami nie uruchamia się w przeglądarce Firefox, więc dodałem „loadmetadata”. Wstrzymuję również poprzedni film, jeśli jest jeden ...

var loadVideo = function(movieUrl) {
    console.log('loadVideo()');
    $videoLoading.show();
    var isReady = function (event) {
            console.log('video.isReady(event)', event.type);
            video.removeEventListener('canplay', isReady);
            video.removeEventListener('loadedmetadata', isReady);
            $videoLoading.hide();
            video.currentTime = 0;
            video.play();
        },
        whenPaused = function() {
            console.log('video.whenPaused()');
            video.removeEventListener('pause', whenPaused);
            video.addEventListener('canplay', isReady, false);
            video.addEventListener('loadedmetadata', isReady, false); // Sometimes Firefox don't trigger "canplay" event...
            video.src = movieUrl; // Change actual source
        };

    if (video.src && !video.paused) {
        video.addEventListener('pause', whenPaused, false);
        video.pause();
    }
    else whenPaused();
};

Poprawka na pewno zadziałała dla mnie, firefox nie obsługuje właściwości canplayani canplaythroughi lodedmetadatamusi zostać dodany (i usunięty później) do obsługi wideo :-(
Lord of freaks

3

To jest moje rozwiązanie:

<video id="playVideo" width="680" height="400" controls="controls">
    <source id="sourceVideo" src="{{video.videoHigh}}" type="video/mp4">
</video>
    <br />
<button class="btn btn-warning" id="{{video.videoHigh}}" onclick="changeSource(this)">HD</button>
<button class="btn btn-warning" id="{{video.videoLow}}" onclick="changeSource(this)">Regular</button>

<script type="text/javascript">
    var getVideo = document.getElementById("playVideo");
    var getSource = document.getElementById("sourceVideo");
    function changeSource(vid) {
        var geturl = vid.id;
        getSource .setAttribute("src", geturl);
        getVideo .load()
        getVideo .play();
        getVideo .volume = 0.5;
    }
</script>

2

Używanie <source />tagów okazało się dla mnie trudne szczególnie w Chrome 14.0.835.202, chociaż działało dobrze dla mnie w FireFox. (Może to oznaczać mój brak wiedzy, ale i tak pomyślałem, że alternatywne rozwiązanie może być przydatne). Skończyło się więc na użyciu <video />tagu i ustawieniu atrybutu src bezpośrednio w tagu wideo. canPlayVideo('<mime type>')Funkcja została wykorzystana do określenia, czy przeglądarka specyficzny mógł odtworzyć film wejściowego. Poniższe działa w FireFox i Chrome.

Nawiasem mówiąc, zarówno FireFox, jak i Chrome odtwarzają format „ogg”, chociaż Chrome zaleca „webm”. Sprawdzam, czy przeglądarka obsługuje "ogg" jako pierwsza tylko dlatego, że inne posty wspominały, że FireFox preferuje źródło ogg jako pierwsze (tj <source src="..." type="video/ogg"/>.). Ale nie testowałem (i bardzo wątpię), czy kolejność w kodzie ma jakiekolwiek znaczenie podczas ustawiania „src” w tagu wideo.

HTML

<body onload="setupVideo();">
    <video id="media" controls="true" preload="auto" src="">
    </video>
</body>

JavaScript

function setupVideo() {
       // You will probably get your video name differently
       var videoName = "http://video-js.zencoder.com/oceans-clip.mp4";

       // Get all of the uri's we support
       var indexOfExtension = videoName.lastIndexOf(".");
       //window.alert("found index of extension " + indexOfExtension);
       var extension = videoName.substr(indexOfExtension, videoName.length - indexOfExtension);
       //window.alert("extension is " + extension);
       var ogguri = encodeURI(videoName.replace(extension, ".ogv"));
       var webmuri = encodeURI(videoName.replace(extension, ".webm"));
       var mp4uri = encodeURI(videoName.replace(extension, ".mp4"));
       //window.alert(" URI is " + webmuri);


       // Get the video element
       var v = document.getElementById("media");
       window.alert(" media is " + v);

       // Test for support
       if (v.canPlayType("video/ogg")) {
            v.setAttribute("src", ogguri);
           //window.alert("can play ogg");
       }
       else if (v.canPlayType("video/webm")) {
           v.setAttribute("src", webmuri);
           //window.alert("can play webm");
       }
       else if (v.canPlayType("video/mp4")) {
           v.setAttribute("src", mp4uri);
           //window.alert("can play mp4");
       }
       else {
           window.alert("Can't play anything");
       }

      v.load();
      v.play();
  }

2

Badam to od dłuższego czasu i próbuję zrobić to samo, więc mam nadzieję, że pomoże to komuś innemu. Używałem crossbrowsertesting.com i testowałem to dosłownie w prawie każdej przeglądarce znanej człowiekowi. Rozwiązanie, które obecnie posiadam, działa w przeglądarce Opera, Chrome, Firefox 3.5+, IE8 +, iPhone 3GS, iPhone 4, iPhone 4s, iPhone 5, iPhone 5s, iPad 1+, Android 2.3+, Windows Phone 8.

Dynamicznie zmieniające się źródła

Dynamiczna zmiana wideo jest bardzo trudna, a jeśli chcesz zastosować rezerwę Flash, musisz usunąć wideo z DOM / strony i dodać je ponownie, aby Flash zaktualizował się, ponieważ Flash nie rozpozna dynamicznych aktualizacji zmiennych Flash. Jeśli zamierzasz używać JavaScript do dynamicznej zmiany, całkowicie usunąłbym wszystkie <source>elementy i po prostu użyłem canPlayTypedo ustawienia srcw JavaScript i breaklub returnpo pierwszym obsługiwanym typie wideo i nie zapomnij dynamicznie aktualizować flasha var mp4. Ponadto niektóre przeglądarki nie zarejestrują zmiany źródła, dopóki nie zadzwonisz video.load(). Uważam, że problem z .load()Tobą można rozwiązać, dzwoniąc po raz pierwszyvideo.pause(). Usunięcie i dodanie elementów wideo może spowolnić przeglądarkę, ponieważ nadal buforuje usunięte wideo, ale istnieje obejście .

Obsługa wielu przeglądarek

Jeśli chodzi o faktyczną część dla różnych przeglądarek, dotarłem również do Video For Everybody . Wypróbowałem już wtyczkę MediaelementJS Wordpress, która, jak się okazało, powodowała znacznie więcej problemów niż rozwiązała. Podejrzewam, że problemy były spowodowane wtyczką Wordpress, a nie biblioteką. Próbuję znaleźć coś, co działa bez JavaScript, jeśli to możliwe. Do tej pory wymyśliłem ten zwykły HTML:

<video width="300" height="150" controls="controls" poster="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" class="responsive">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg" />
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4" />
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm" />
<source src="http://alex-watson.net/wp-content/uploads/2014/07/big_buck_bunny.iphone.mp4" type="video/mp4" />
<source src="http://alex-watson.net/wp-content/uploads/2014/07/big_buck_bunny.iphone3g.mp4" type="video/mp4" />
<object type="application/x-shockwave-flash" data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" width="561" height="297">
    <param name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" />
    <param name="allowFullScreen" value="true" />
    <param name="wmode" value="transparent" />
    <param name="flashVars" value="config={'playlist':['http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg',{'url':'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4','autoPlay':false}]}" />
    <img alt="No Video" src="http://sandbox.thewikies.com/vfe-generator/images/big-buck-bunny_poster.jpg" width="561" height="297" title="No video playback capabilities, please download the video below" />
</object>
<strong>Download video:</strong>  <a href="video.mp4">MP4 format</a> | <a href="video.ogv">Ogg format</a> | <a href="video.webm">WebM format</a>
</video>

Ważne uwagi :

  • Skończyło się na umieszczeniu ogg jako pierwszego, <source>ponieważ Mac OS Firefox kończy próbę odtworzenia wideo, jeśli napotka MP4 jako pierwszy <source>.
  • Prawidłowe typy MIME są ważne. Pliki .ogv powinny być video/ogg, a nie video/ogv
  • Jeśli masz wideo HD, najlepszym transkoderem, jaki znalazłem dla plików OGG w jakości HD, jest Firefogg
  • .iphone.mp4Plik jest dla iPhone 4+ który będzie tylko odtwarzać filmy, które są MPEG-4 H.264 Baseline 3 z wideo i dźwiękiem AAC. Najlepszym transkoderem, jaki znalazłem dla tego formatu, jest hamulec ręczny, użycie ustawień wstępnych iPhone'a i iPoda Touch będzie działać na iPhonie 4+, ale aby iPhone 3GS działał, musisz użyć ustawienia wstępnego iPoda, które ma znacznie niższą rozdzielczość, które dodałem jako video.iphone3g.mp4.
  • W przyszłości będziemy mogli używać mediaatrybutu w <source>elementach, aby kierować reklamy na urządzenia mobilne z zapytaniami o media, ale obecnie starsze urządzenia Apple i Android nie obsługują go wystarczająco dobrze.

Edycja :

  • Nadal używam Video For Everybody, ale teraz przeszedłem na używanie FlowPlayera, aby kontrolować rezerwę Flash, która ma niesamowite API JavaScript, które może być używane do kontrolowania tego.

Wydaje się, że jest to odpowiedź na pytanie „Jak odtwarzać pliki wideo w przeglądarce?” a nie to pytanie „Jak ustawić playlistę dla mojego filmu?”.
Quentin,

@Quentin To było na początku, ponieważ tak znalazłem to pytanie przez Google, a OP powiedział, że próbuje zbudować odtwarzacz wideo, który działa wszędzie. Zaktualizowałem odpowiedź, aby odpowiedzieć również na jego dynamiczne pytanie.
Alex W,

2

Mam podobną aplikację internetową i wcale nie mam takiego problemu. Robię coś takiego:

var sources = new Array();

sources[0] = /path/to/file.mp4
sources[1] = /path/to/another/file.ogg
etc..

wtedy kiedy chcę zmienić źródła, mam funkcję, która robi coś takiego:

this.loadTrack = function(track){
var mediaSource = document.getElementsByTagName('source')[0];
mediaSource.src = sources[track];

    var player = document.getElementsByTagName('video')[0];
    player.load();

}

Robię to, aby użytkownik mógł przejść przez listę odtwarzania, ale możesz sprawdzić userAgent, a następnie załadować w ten sposób odpowiedni plik. Próbowałem używać wielu tagów źródłowych, tak jak sugerowali wszyscy w internecie, ale okazało się, że manipulowanie atrybutem src pojedynczego tagu źródłowego jest znacznie czystsze i znacznie bardziej niezawodne. Powyższy kod został napisany z pamięci, więc mogłem przeoczyć niektóre szczegóły hte, ale ogólna idea polega na dynamicznej zmianie atrybutu src tagu źródłowego za pomocą javascript, jeśli jest to konieczne.


1

Spróbuj przenieść źródło OGG na górę. Zauważyłem, że Firefox czasami jest zdezorientowany i zatrzymuje gracza, gdy ten, w który chce grać, OGG, nie jest pierwszy.

Warte spróbowania.


1

Inny sposób, w jaki możesz to zrobić w Jquery.

HTML

<video id="videoclip" controls="controls" poster="" title="Video title">
    <source id="mp4video" src="video/bigbunny.mp4" type="video/mp4"  />
</video>

<div class="list-item">
     <ul>
         <li class="item" data-video = "video/bigbunny.mp4"><a href="javascript:void(0)">Big Bunny.</a></li>
     </ul>
</div>

Jquery

$(".list-item").find(".item").on("click", function() {
        let videoData = $(this).data("video");
        let videoSource = $("#videoclip").find("#mp4video");
        videoSource.attr("src", videoData);
        let autoplayVideo = $("#videoclip").get(0);
        autoplayVideo.load();
        autoplayVideo.play();
    });

0

Korzystanie z JavaScript i jQuery:

<script src="js/jquery.js"></script>
...
<video id="vid" width="1280" height="720" src="v/myvideo01.mp4" controls autoplay></video>
...
function chVid(vid) {
    $("#vid").attr("src",vid);
}
...
<div onclick="chVid('v/myvideo02.mp4')">See my video #2!</div>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.