관련 지식
javascript, video, HTMLVideoElement, HTMLMediaElement

유튜브나 POOQ 같은 동영상 재생 사이트에서 동영상을 보는 중입니다. 스크롤을 내려서 댓글들을 보는 중에도 영상은 계속 보고 싶습니다. 어떻게 하면 될까요?

가장 생각하기 쉬운 방법은 스크롤이 발생해서 영상이 가려졌을때 영상 위치의 속성을 변경하여 화면 하단 같은 곳으로 고정하는 것입니다.

그러나 영상 화면에 재생, 스킵 같은 많은 컨트롤 메뉴와 이벤트가 있을수 있습니다. 재생 위치가 변경되며 원래의 기능과 다른 기능을 가져야할때 기존 기능이 많을수록 매우 번거로운 작업이 될 것입니다. 그럴땐 기존 영상의 위치를 바꾸지 않고 새로 보조 영상을 만드는것이 좋습니다.

이때 주의할 것은 재생하던 영상과의 싱크입니다. 메인 영상이 10초 정도 재생된 상태에서 보조 영상이 만들어 졌을때 처음부터 재생되면 안되겠죠? 어떻게 하면 될까요?

HTMLVideoElement

영상 재생시 사용하는 <video> 태그는 HTMLVideoElement 인데 이것은 HTMLMediaElement를 상속했습니다. 따라서 HTMLMediaElement 요소를 사용할 수가 있는데 captureStream() 함수가 있습니다. 재생중인 미디어의 스트림 소스를 얻어낼수 있는 함수 입니다. 따라서 아래와 같이 매우 단순한 방법으로 보조 영상을 만들수 있습니다.

  1. var mainVideo = document.getElementById("main");
  2. var subVideo = document.getElementById("sub");
  3. subVideo.srcObject = mainVideo.captureStream();

그런데 보조 영상 재생 전후로 볼륨이 미묘하게 커진듯한 느낌을 받습니다. 두개의 영상이 동시에 재생되며 볼륨이 커진듯한 느낌을 주는것인데 따라서 영상 한쪽의 소리는 뮤트 시켜야 합니다. 메인 영상의 볼륨을 살리고 보조 영상쪽 소리를 뮤트하는게 좋겠죠?

  1. subVideo.volume = 0;

완전히 싱크가 되는 보조 영상이 만들어졌습니다.

메인 영상과 보조 영상의 재생관계

메인 영상을 pause() 하면 재생되는 스트림이 없으므로 보조 영상도 같이 멈추게 됩니다.
메인 영상을 play() 하면 보조 영상도 다시 재생 됩니다.
보조 영상을 pause() 하면 메인 영상은 계속 재생되고 보조 영상만 pause() 됩니다.
보조 영상을 play() 하면 재생중인 메인 영상과 같은 싱크로 재생 됩니다.

따라서 보조 영상 메뉴에 영상 컨트롤 버튼을 넣을 경우 메인 영상만 컨트롤 하면 되겠습니다.

정리

아래 최종 샘플을 테스트하기 위해선 동영상 파일이 필요합니다. 동영상 파일을 별도로 올리진 않았으니 각자 가지고 있는 적당한 mp4 파일로 대체해서 확인해 보시기 바랍니다.

참고
HTMLMediaElement : https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
HTMLVideoElement : https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement

최종 샘플

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>CSS Template</title>
  5. <meta charset="utf-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <style>
  8. video { border:1px solid blue;}
  9. .main {width:400px;}
  10. .sub {width:300px; }
  11. </style>
  12. </head>
  13. <body>
  14. <div>
  15. <p><button id="mainplay">main play</button>&nbsp;<button id="mainpause">main pause</button></p>
  16. <video id="main" class="main" src="/인트로.mp4" autoplay></video>
  17. </div>
  18. <div style="position:fixed; bottom:0; right:0;">
  19. <p><button id="subplay">sub play</button>&nbsp;<button id="subpause">sub pause</button></p>
  20. <video id="sub" class="sub" autoplay></video>
  21. </div>
  22. <div style="height:800px"></div>
  23. <script>
  24. var mainVideo = document.getElementById('main');
  25. var subVideo = document.getElementById('sub');
  26. subVideo.addEventListener('loadstart', function(e) {
  27. console.log('play');
  28. });
  29. subVideo.addEventListener('pause', function(e) {
  30. console.log('pause');
  31. });
  32. subVideo.volume = 0; //볼륨 0으로
  33. subVideo.srcObject = mainVideo.captureStream();
  34. //메인 영상 일시 정지
  35. document.getElementById('mainplay').addEventListener('click', function(e) {
  36. mainVideo.play();
  37. });
  38. //메인 영상 재생
  39. document.getElementById('mainpause').addEventListener('click', function(e) {
  40. mainVideo.pause();
  41. });
  42. //보조 영상 일시 정지
  43. document.getElementById('subplay').addEventListener('click', function(e) {
  44. subVideo.play();
  45. });
  46. //보조 영상 재생
  47. document.getElementById('subpause').addEventListener('click', function(e) {
  48. subVideo.pause();
  49. });
  50. </script>
  51. </body>
  52. </html>