Synchronizacja dwóch filmów z YouTube

Mam dwa identyczne Filmy na YouTube osadzone na tej samej stronie. Chciałbym, aby oba były zsynchronizowane, oto moje wymagania/uwagi:

  • oba filmy muszą zaczynać się w tym samym czasie
  • Gdy wideo jest odtwarzane / wstrzymywane przez użytkownika, inne wideo robi to samo
    • jest to dość proste poprzez API
  • gdy jeden bufor wideo zatrzymuje się, aby poczekać i rozpoczyna się, gdy oba są gotowe
  • potrzebuję tylko dźwięku z jednego filmu
  • synchronizacja dokładności nie musi być milisekundy idealne, po prostu niezawodne
  • jeden film będzie używany jako tło wideo
    • ten film będzie nieco rozmyty (przy użyciu CSS3 blur), więc jakość nie jest super niezbędna

Próbowałem użyć interfejsu API YouTube js, aby słuchać zmian stanu odtwarzacza i próbować synchronizować oba filmy, jednak nie było to tak wiarygodne, jak miałem nadzieję. Część kodu zamieszczę poniżej.

Jedno zastrzeżenie jest takie, że jeden film będzie wyglądał na większy niż inne, więc YouTube może zapewnić wyższą jakość wideo dla tego.

Ponieważ używam CSS3 blur mogę używać tylko najnowszych przeglądarek Webkit, więc rozwiązanie, które działa tylko na tych (a nie FF/IE) nie jest problemem.

Moje pytanie brzmi: , zgodnie z powyższymi wymaganiami, czy istnieje sposób na synchronizację tych dwóch filmów? Rozważałem, czy można użyć canvas API do "przerysowania" wideo, ale po zbadaniu stwierdziłem, że nie będzie to możliwe.

buffering = false;

var buffer_control = function(buffering_video, sibling_video, state) {

switch ( state ) {

    case 1: // play

        if ( buffering === true ) {

            console.error('restarting after buffer');

            // pause both videos, we want to make sure they are both at the same time
            buffering_video.pauseVideo();
            sibling_video.pauseVideo();

            // get the current time of the video being buffered...
            var current_time = buffering_video.getCurrentTime();

            // ... and pull the sibling video back to that time
            sibling_video.seekTo(current_time, true);

            // finally, play both videos
            buffering_video.playVideo();
            sibling_video.playVideo();

            // unset the buffering flag
            buffering = false;

        }

        break;

    case 3: // buffering


        console.error('buffering');

        // set the buffering flag
        buffering = true;

        // pause the sibling video
        sibling_video.pauseVideo();

        break;

}

}
Author: Ben Everard, 2013-11-11

1 answers

Twój projekt jest dość interesujący, dlatego postanowiłem spróbować Ci pomóc. Nigdy nie używałem interfejsu API youtube, ale próbowałem trochę kodowania i może to być początek dla Ciebie.

Oto kod, który próbowałem i wydaje się działać całkiem dobrze, na pewno wymaga pewnych ulepszeń (nie próbowałem obliczyć przesunięcia między dwoma odtwarzanymi filmami, ale pozostawienie ich niemutych pokazuje niedopasowanie i brzmi legalnie) {]}

Zaczynamy:

Zacznijmy od jakiegoś html podstawy

<!DOCTYPE html>
<html>
    <head>

Dodajemy absolutną pozycję dla odtwarzacza pierwszoplanowego, aby nakładał się na ten odtwarzający wideo w tle (do testów)

        <style>
            #player2{position:absolute;left:195px;top:100px;}
        </style>
    </head>
<body>

JQuery jest tutaj używany do zanikania / wyłączania odtwarzaczy (zobaczysz dlaczego poniżej), ale możesz użyć podstawowego JS

    <script src="jquery-1.10.2.min.js"></script>

Znaczniki (i odtwarzacze wideo) zastąpią te znaczniki .

    <div id="player1"></div>    <!-- Background video player -->
    <div id="player2"></div>    <!-- Foreground video player -->

    <script>

Ten kod ładuje kod API IFrame Player asynchronicznie.

        var tag = document.createElement('script');

        tag.src = "https://www.youtube.com/iframe_api";
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

Ta funkcja tworzy (i Odtwarzacze YouTube) po pobraniu kodu API. Zwróć uwagę na funkcje wywołania zwrotnego: onPlayer1Ready i onPlayer1StateChange

        var player1;
        var player2;
        function onYouTubeIframeAPIReady() {
            player1 = new YT.Player('player1', {
                                  height: '780',
                                  width: '1280',
                                  videoId: 'M7lc1UVf-VE',
                                  playerVars: { 'autoplay': 0, 'controls': 0 },
                                  events: {
                                        'onReady': onPlayer1Ready,
                                        'onStateChange': onPlayer1StateChange
                                  }
                             });
            player2 = new YT.Player('player2', {
                                  height: '390',
                                  width: '640',
                                  videoId: 'M7lc1UVf-VE',
                                  events: {
                                       'onReady': onPlayer2Ready,
                                       'onStateChange': onPlayer2StateChange
                                  }
                              });
        }


        var player1Ready = false;
        var player2Ready = false;

Więc teraz jest interesująca część kodu. Główny problem w projekcie synchronizacji jest związany z faktem, że filmy muszą być buforowane przed ich uruchomieniem. W rzeczywistości API Nie zapewnia żadnej intuicyjnej funkcji wstępnego ładowania filmów (ze względu na problemy z przepustowością (po stronie klienta i serwera). Więc musimy być trochę podstępni.
Kroki do wstępnego załadowania a filmy są następujące:

    [[39]} Ukryj odtwarzacz, aby kolejne kroki nie były widoczne dla użytkownika); [40]}
  • wyciszyć odtwarzacz ( player.mute():Void );
  • emulować skok w osi czasu, aby rozpocząć buforowanie ( player.seekTo(seconds:Number, allowSeekAhead:Boolean):Void );
  • poczekaj na zdarzenie zmiany stanu równe YT.PlayerState.PLAYING;
  • Pauza wideo ( player.pauseVideo():Void );
  • Przewiń wideo za pomocą player.seekTo(seconds:Number, allowSeekAhead:Boolean):Void;
  • Odblokuj odtwarzacz ( player.unMute():Void );
  • Pokaż graczowi.

Musisz wstępnie załadować swoje dwa filmy.

        var preloading1 = false;
        var preloading2 = false;

API wywoła te funkcje, gdy odtwarzacze wideo będą gotowe.

        function onPlayer1Ready(event) 
        {
            player1Ready = true;
            preloading1 = true;       // Flag the player 1 preloading
            player1.mute();           // Mute the player 1
            $( "#player1" ).hide();   // Hide it
            player1.seekTo(1);        // Start the preloading and wait a state change event
        }

        function onPlayer2Ready(event) {
            player2Ready = true;      // The foreground video player is not preloaded here
        }

API wywołuje tę funkcję, gdy zmienia się stan odtwarzacza wideo w tle.

        function onPlayer1StateChange(event) 
        {
            if (event.data == YT.PlayerState.PLAYING ) {
                if(preloading1)
                {
                    prompt("Background ready");     // For testing
                    player1.pauseVideo();           // Pause the video
                    player1.seekTo(0);              // Rewind
                    player1.unMute();           // Comment this after test
                    $( "#player1" ).show();         // Show the player
                    preloading1 = false;

                    player2Ready = true;
                    preloading2 = true;             // Flag for foreground video preloading
                    player2.mute();
                    //$( "#player2" ).hide();
                    player2.seekTo(1);              // Start buffering and wait the event
                }
                else
                    player2.playVideo();            // If not preloading link the 2 players PLAY events
            }

            else if (event.data == YT.PlayerState.PAUSED ) {
                if(!preloading1)
                    player2.pauseVideo();           // If not preloading link the 2 players PAUSE events
            }
            else if (event.data == YT.PlayerState.BUFFERING ) {
                if(!preloading1)
                {
                    player2.pauseVideo();           // If not preloading link the 2 players BUFFERING events
                }
            }
            else if (event.data == YT.PlayerState.CUED ) {
                if(!preloading1)
                    player2.pauseVideo();           // If not preloading link the 2 players CUEING events
            }
            else if (event.data == YT.PlayerState.ENDED ) {
                player2.stopVideo();                // If not preloading link the 2 players ENDING events
            }
        }

API wywołuje tę funkcję, gdy zmienia się stan odtwarzacza wideo na pierwszym planie.

        function onPlayer2StateChange(event) {
            if (event.data == YT.PlayerState.PLAYING ) {
                if(preloading2)
                {
                    //prompt("Foreground ready");
                    player2.pauseVideo();           // Pause the video
                    player2.seekTo(0);              // Rewind
                    player2.unMute();               // Unmute
                    preloading2 = false;

                    $( "#player2" ).show(50, function() {

Oto część kodeksu, która działa dziwnie. Nieuwzględnienie poniższej linii spowoduje, że synchronizacja będzie dość zła, ale jeśli ją skomentujesz, będziesz musiał kliknąć dwa razy w grze button ale synchronizacja będzie wyglądać o wiele lepiej.

                       //player2.playVideo();
                    });
                }
                else
                    player1.playVideo();
            }
            else if (event.data == YT.PlayerState.PAUSED ) {
                if(/*!preloading1 &&*/ !preloading2)
                    player1.pauseVideo();
            }
            else if (event.data == YT.PlayerState.BUFFERING ) {
                if(!preloading2)
                {
                    player1.pauseVideo();
                    //player1.seekTo(... // Correct the offset here
                }
            }
            else if (event.data == YT.PlayerState.CUED ) {
                if(!preloading2)
                    player1.pauseVideo();
            }
            else if (event.data == YT.PlayerState.ENDED ) {
                player1.stopVideo();
            }
        }


        </script>
    </body>
</html>

Zauważ, że widoki mogą nie być liczone za pomocą tego kodu.

Jeśli chcesz Kod bez wyjaśnień możesz przejść tutaj: http://jsfiddle.net/QtBlueWaffle/r8gvX/1/

2016 Update Podgląd Na Żywo

Mam nadzieję, że to pomoże.
 29
Author: ThisIsSparta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-16 17:49:14