Подтвердить что ты не робот

Сохранение двух видеороликов YouTube в синхронизации друг с другом

У меня есть два одинаковых видеоролика YouTube, встроенных на одну страницу. Я бы хотел, чтобы они оба синхронизировались, вот мои требования/примечания:

  • Оба видео должны запускаться одновременно.
  • Когда видео воспроизводится/приостанавливается пользователем, другое видео делает то же самое
    • Это довольно просто с помощью API
  • Когда одно видео буферизует остальные остановки для ожидания и запускается, когда они оба готовы
  • Мне нужен только звук с одного видео.
  • Точность синхронизации не должна быть миллисекундой совершенной, просто надежной.
  • Одно видео будет использоваться в качестве фонового видео
    • Это видео будет слегка размытым (с использованием размытия CSS3), поэтому качество не супер существенное

Я попытался использовать JS API YouTube, чтобы прослушивать изменения состояния проигрывателя и пытаться синхронизировать оба видео, однако это было не так надежно, как я надеялся. Я отправлю часть кода для этого ниже.

Одно из предостережений заключается в том, что одно видео будет больше, чем другое, поэтому YouTube может предоставить для него более качественное видео.

Поскольку я использую размытие CSS3, я могу использовать только последние браузеры Webkit, поэтому решение, работающее только на них (а не на FF/IE), не является проблемой.

Мой вопрос в том, что, для требований выше, есть ли способ сохранить эти два видео в синхронизации? Я подумал, можно ли использовать API-интерфейс canvas для "перерисовки" видео, но после исследования выяснилось, что это не будет возможным.

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;

}

}
4b9b3361

Ответ 1

Ваш проект интересен, поэтому я решил помочь вам. Я никогда не использовал API-интерфейс youtube, но я пробовал кодирование, и это может быть началом для вас.

Итак, вот код, который я пробовал, и, похоже, он работает неплохо, он, безусловно, нуждается в некоторых улучшениях (я не пытался рассчитать смещение между двумя воспроизведенными видео, но позволяя им включать звук, показывает несоответствие, и это звучит законно )

Здесь мы идем:

Начнем с некоторых html-основ

<!DOCTYPE html>
<html>
    <head>

Мы добавляем абсолютное позиционирование для игрока переднего плана, чтобы оно накладывалось на тот, который воспроизводит фоновое видео (для тестирования)

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

jQuery используется здесь, чтобы угаснуть игроков/вы увидите, почему ниже), но вы можете использовать базовый JS

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

iframe > (и видеоплееры) заменят эти <div> .

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

    <script>

Этот код загружает код API IFrame Player асинхронно.

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

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

Эта функция создает <iframes> (и игроков YouTube) после загрузки кода API. Обратите внимание на функции обратного вызова: onPlayer1Ready и 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;

Итак, теперь это интересная часть кода. Основная проблема в вашем проекте синхронизации связана с тем, что перед запуском их необходимо буферизовать. На самом деле API не предоставляет какой-либо интуитивной функции для предварительной загрузки видео (из-за проблем с пропускной способностью (на стороне клиента и сервера). Поэтому нам нужно немного запутаться.
Действия по предварительной загрузке видео:

  • Скрыть проигрыватель, чтобы следующие действия не были видны для пользователя);
  • Отключить плеер (player.mute():Void);
  • Эмуляция перехода по временной шкале для запуска буферизации (player.seekTo(seconds:Number, allowSeekAhead:Boolean):Void);
  • Подождите, пока событие изменения состояния равно YT.PlayerState.PLAYING;
  • Приостановить видео (player.pauseVideo():Void);
  • Перемотка видео с помощью player.seekTo(seconds:Number, allowSeekAhead:Boolean):Void;
  • Включить проигрыватель (player.unMute():Void);
  • Показать игрока.

Вам нужно предварительно загрузить два видео.

        var preloading1 = false;
        var preloading2 = false;

API будет вызывать эти функции, когда видеоплееры готовы.

        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 вызывает эту функцию, когда состояние фонового видеоплеера изменяется.

        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 вызывает эту функцию при изменении состояния видеопроигрывателя переднего плана.

        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() {

Вот часть кода, который действует странно. Разоружение строки ниже сделает синхронизацию довольно плохим, но если вы ее прокомментируете, вам нужно нажать дважды на кнопке PLAY НО, синхронизация будет выглядеть лучше.

                       //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>

Обратите внимание, что представления могут не учитываться с помощью этого кода.

Если вам нужен код без объяснений, вы можете перейти сюда: http://jsfiddle.net/QtBlueWaffle/r8gvX/1/

Обновление 2016 Live Preview

Надеюсь, что это поможет.