/**
 * @파일 html5.js
 */
'./tech.js'에서 기술 가져오기;
import * as Dom from '../utils/dom.js';
import * as Url from '../utils/url.js';
'../utils/log.js'에서 로그 가져오기;
* '../utils/browser.js'에서 브라우저로 가져오기;
'글로벌/문서'에서 문서 가져오기;
'글로벌/창'에서 창 가져오기;
'../utils/obj'에서 {assign} 가져오기;
'../utils/merge-options.js'에서 mergeOptions 가져오기;
'../utils/string-cases.js'에서 {toTitleCase} 가져오기;
'../tracks/track-types'에서 {NORMAL as TRACK_TYPES, REMOTE} 가져오기;
'./setup-sourceset'에서 setupSourceset 가져오기;
import defineLazyProperty from '../utils/define-lazy-property.js';
'../utils/promise'에서 {silencePromise} 가져오기;

/**
 * HTML5 미디어 컨트롤러 - HTML5 미디어 API용 래퍼
 *
 * @mixes Tech~SourceHandlerAdditions
 * @extends 기술
 */
클래스 Html5 확장 기술 {

  /**
  * 이 기술의 인스턴스를 만듭니다.
  *
  * @param {객체} [옵션]
  * 플레이어 옵션의 키/값 저장소.
  *
  * @param {Component~ReadyCallback} 준비 완료
  * `HTML5` Tech가 준비되면 호출하는 콜백 함수.
  */
  생성자(옵션, 준비) {
    super(옵션, 준비);

    const 소스 = 옵션.소스;
    let crossoriginTracks = false;

    this.featuresVideoFrameCallback = this.featuresVideoFrameCallback && this.el_.tagName === '동영상';

    // 제공되는 경우 소스를 설정합니다.
    // 1) 소스가 새로운 것인지 확인(그렇지 않은 경우 재생이 중단되지 않도록 원본을 유지하려고 함)
    // 2) 초기에 태그의 네트워크 상태가 실패했는지 확인하고 실패했다면 소스를 재설정합니다.
    // 어쨌든 오류가 발생합니다.
    만약 (출처 && (this.el_.currentSrc !== 소스.src || (옵션.태그 && options.tag.initNetworkState_ === 3))) {
      this.setSource(소스);
    } else {
      this.handleLateInit_(this.el_);
    }

    // 늦은 sourceset/초기화 이후에 sourceset 설정
    if (options.enableSourceset) {
      this.setupSourcesetHandling_();
    }

    this.isScrubbing_ = 거짓;

    if (this.el_.hasChildNodes()) {

      const 노드 = this.el_.childNodes;
      let nodesLength = nodes.length;
      const removeNodes = [];

      동안 (nodesLength--) {
        const 노드 = 노드[nodesLength];
        const nodeName = node.nodeName.toLowerCase();

        if (노드 이름 === '트랙') {
          if (!this.featuresNativeTextTracks) {
            // 내장 플레이어가 사용하지 않도록 비디오 태그 트랙을 비웁니다.
            // 이것은 HTML5 브라우저가 태그를 읽는 것을 멈출 만큼 충분히 빠르지 않을 수 있습니다.
            // 따라서 수동으로 수행하는 경우 기본 트랙을 꺼야 합니다.
            // 캡션 및 자막. videoElement.text트랙
            removeNodes.push(노드);
          } else {
            // HTMLTrackElement 및 TextTrack을 원격 목록에 저장
            this.remoteTextTrackEls().addTrackElement_(노드);
            this.remoteTextTracks().addTrack(node.track);
            this.textTracks().addTrack(node.track);
            if (!crossorigin트랙 &&
                !this.el_.hasAttribute('크로스오리진') &&
                Url.isCrossOrigin(node.src)) {
              crossoriginTracks = 참;
            }
          }
        }
      }

      에 대한 (하자 i = 0; i < removeNodes.length; i++) {
        this.el_.removeChild(removeNodes[i]);
      }
    }

    this.proxyNativeTracks_();
    if (this.featuresNativeTextTracks && crossoriginTracks) {
      log.warn('텍스트 트랙이 다른 출처에서 로드되고 있지만 crossorigin 속성이 사용되지 않습니다.\n' +
            '텍스트 트랙이 로드되지 않을 수 있습니다.');
    }

    // 기본 재생 중에 iOS Safari가 메타데이터 텍스트 트랙을 비활성화하지 못하도록 합니다.
    this.restoreMetadataTracksInIOSNativePlayer_();

    // 네이티브 컨트롤을 사용해야 하는지 결정
    // 우리의 목표는 어디에서나 모바일 솔리드에서 사용자 지정 컨트롤을 얻는 것입니다.
    // 그래서 우리는 이것을 모두 함께 제거할 수 있습니다. 지금은 사용자 지정을 차단합니다.
    // Chrome Pixel과 같은 터치 지원 노트북의 컨트롤
    if ((browser.TOUCH_ENABLED || browser.IS_IPHONE ||
        브라우저.IS_NATIVE_ANDROID) && options.nativeControlsForTouch === 참) {
      this.setControls(참);
    }

    // iOS에서는 `webkitbeginfullscreen` 및 `webkitendfullscreen`을 프록시하려고 합니다.
    // `fullscreenchange` 이벤트로
    this.proxyWebkitFullscreen_();

    this.triggerReady();
  }

  /**
   * `HTML5` 미디어 요소를 폐기하고 모든 트랙을 제거합니다.
   */
  폐기() {
    만약 (이것.el_ && this.el_.resetSourceset_) {
      this.el_.resetSourceset_();
    }
    Html5.disposeMediaElement(this.el_);
    this.options_ = null;

    // 기술이 에뮬레이트된 트랙 목록 지우기를 처리합니다.
    super.dispose();
  }

  /**
   * 언제 감지할 수 있도록 미디어 요소를 수정합니다.
   * 소스가 변경되었습니다. 소스가 변경된 직후 `sourceset` 실행
   */
  setupSourcesetHandling_() {
    setupSourceset(이);
  }

  /**
   * iOS Safari 기본 플레이어에서 캡션 트랙이 활성화되면 다른 모든
   * 트랙이 비활성화되어(메타데이터 트랙 포함) 모든 트랙이 무효화됩니다.
   * 관련 큐 포인트. 이렇게 하면 메타데이터 트랙이 사전 전체 화면으로 복원됩니다.
   * 이러한 경우 큐 포인트가 불필요하게 손실되지 않도록 상태를 유지합니다.
   *
   * @사적인
   */
  restoreMetadataTracksInIOSNativePlayer_() {
    const textTracks = this.textTracks();
    let metadataTracksPreFullscreenState;

    // 모든 메타데이터 트랙의 현재 상태에 대한 스냅샷 캡처
    const takeMetadataTrackSnapshot = () => {
      metadataTracksPreFullscreenState = [];

      에 대한 (하자 i = 0; i < textTracks.length; i++) {
        const track = textTracks[i];

        if (track.kind === '메타데이터') {
          metadataTracksPreFullscreenState.push({
            길,
            storedMode: 트랙.모드
          });
        }
      }
    };

    // 각 메타데이터 트랙의 초기 상태를 스냅샷하고 스냅샷을 업데이트합니다.
    // 트랙 '변경' 이벤트가 있을 때마다
    takeMetadataTrackSnapshot();
    textTracks.addEventListener('변경', takeMetadataTrackSnapshot);

    this.on('처리', () => textTracks.removeEventListener('변경', takeMetadataTrackSnapshot));

    const restoreTrackMode = () => {
      에 대한 (하자 i = 0; i < metadataTracksPreFullscreenState.length; i++) {
        const storedTrack = metadataTracksPreFullscreenState[i];

        if (storedTrack.track.mode === '비활성화' && storedTrack.track.mode !== storedTrack.storedMode) {
          storedTrack.track.mode = storedTrack.storedMode;
        }
      }
      // 이 핸들러가 첫 번째 '변경' 이벤트에서만 실행되기를 원합니다.
      textTracks.removeEventListener('변경', restoreTrackMode);
    };

    // 전체 화면 재생에 들어가면 스냅샷 업데이트를 중지하고
    // 모든 트랙 모드를 전체 화면 이전 상태로 복원
    this.on('webkitbeginfullscreen', () => {
      textTracks.removeEventListener('변경', takeMetadataTrackSnapshot);

      // 이전에 제거되지 않은 경우를 대비하여 추가하기 전에 수신기를 제거합니다.
      textTracks.removeEventListener('변경', restoreTrackMode);
      textTracks.addEventListener('변경', restoreTrackMode);
    });

    // 전체 화면을 나간 후 스냅샷 업데이트를 다시 시작합니다.
    this.on('webkitendfullscreen', () => {
      // 이전에 제거되지 않은 경우를 대비하여 추가하기 전에 수신기를 제거합니다.
      textTracks.removeEventListener('변경', takeMetadataTrackSnapshot);
      textTracks.addEventListener('변경', takeMetadataTrackSnapshot);

      // 전체 화면 재생 중에 트리거되지 않은 경우 restoreTrackMode 핸들러를 제거합니다.
      textTracks.removeEventListener('변경', restoreTrackMode);
    });
  }

  /**
   * 주어진 유형에 대한 트랙의 강제 무시 시도
   *
   * @param {string} type - 재정의할 트랙 유형, 가능한 값에는 '오디오',
   * '동영상', 그리고 '텍스트'.
   * @param {boolean} override - true로 설정하면 기본 오디오/비디오가 무시됩니다.
   * 그렇지 않으면 기본 오디오/비디오가 잠재적으로 사용됩니다.
   * @사적인
   */
  overrideNative_(유형, 재정의) {
    // 동작 변경이 없으면 리스너를 추가/제거하지 않습니다.
    if (재정의 !== this[`featuresNative${type}Tracks`]) {
      반품;
    }

    const lowerCaseType = type.toLowerCase();

    if (this[`${lowerCaseType}TracksListeners_`]) {
      Object.keys(this[`${lowerCaseType}TracksListeners_`]).forEach((eventName) => {
        const elTracks = this.el()[`${lowerCaseType}트랙`];

        elTracks.removeEventListener(eventName, this[`${lowerCaseType}TracksListeners_`][eventName]);
      });
    }

    this[`featuresNative${type}Tracks`] = !override;
    this[`${lowerCaseType}TracksListeners_`] = null;

    this.proxyNativeTracksForType_(lowerCaseType);
  }

  /**
   * 기본 오디오 트랙을 강제로 무시하려고 시도합니다.
   *
   * @param {boolean} override - true로 설정하면 기본 오디오가 무시됩니다.
   * 그렇지 않으면 기본 오디오가 잠재적으로 사용됩니다.
   */
  overrideNativeAudioTracks(재정의) {
    this.overrideNative_('오디오', 재정의);
  }

  /**
   * 기본 비디오 트랙을 강제로 무시하려고 시도합니다.
   *
   * @param {boolean} override - true로 설정하면 기본 동영상이 무시됩니다.
   * 그렇지 않으면 네이티브 비디오가 잠재적으로 사용됩니다.
   */
  overrideNativeVideoTracks(재정의) {
    this.overrideNative_('동영상', override);
  }

  /**
   * 주어진 유형의 프록시 네이티브 트랙 목록 이벤트를 우리 트랙에
   * 재생 중인 브라우저가 해당 유형의 트랙 목록을 지원하는지 여부를 나열합니다.
   *
   * @param {string} 이름 - 트랙 유형; 값에는 '오디오', '비디오' 및 '텍스트'가 포함됩니다.
   * @사적인
   */
  proxyNativeTracksForType_(이름) {
    const 소품 = TRACK_TYPES[이름];
    const elTracks = this.el()[props.getterName];
    const techTracks = this[props.getterName]();

    if (!this[`featuresNative${props.capitalName}트랙`] ||
        !el트랙 ||
        !elTracks.addEventListener) {
      반품;
    }
    const 리스너 = {
      변화: (e) => {
        const 이벤트 = {
          유형: '변경',
          대상: techTracks,
          currentTarget: techTracks,
          srcElement: techTracks
        };

        techTracks.trigger(이벤트);

        // 텍스트 트랙 변경 이벤트인 경우
        // 원격 텍스트 트랙 목록. 이로 인해 잠재적으로 잘못된 긍정이 발생할 수 있습니다.
        // 비원격 트랙에서 변경 이벤트를 받고
        // 원격 텍스트 추적 목록에서 이벤트를 트리거했지만
        // 해당 트랙을 포함합니다. 그러나 모범 사례는
        // 트랙 목록 및 적절한 모드 값 검색, 그래서,
        // 이것은 문제를 일으키지 않아야 합니다.
        if (이름 === '텍스트') {
          this[REMOTE.remoteText.getterName]().trigger(event);
        }
      },
      추가트랙(e) {
        techTracks.addTrack(e.track);
      },
      제거트랙(e) {
        techTracks.removeTrack(e.track);
      }
    };
    const removeOldTracks = 함수() {
      const removeTracks = [];

      에 대한 (하자 i = 0; i < techTracks.length; i++) {
        발견하자 = 거짓;

        에 대한 (하자 j = 0; j < elTracks.length; j++) {
          if (elTracks[j] === techTracks[i]) {
            발견 = 참;
            부서지다;
          }
        }

        경우 (!발견) {
          removeTracks.push(techTracks[i]);
        }
      }

      동안 (removeTracks.length) {
        techTracks.removeTrack(removeTracks.shift());
      }
    };

    this[props.getterName + 'Listeners_'] = 리스너;

    Object.keys(listeners).forEach((eventName) => {
      const listener = listeners[이벤트 이름];

      elTracks.addEventListener(eventName, listener);
      this.on('처리', (e) => elTracks.removeEventListener(eventName, listener));
    });

    // 더 이상 사용되지 않는 (네이티브) 트랙 제거
    this.on('loadstart', removeOldTracks);
    this.on('처리', (e) => this.off('loadstart', removeOldTracks));
  }

  /**
   * 우리가 재생하는 브라우저인 경우 모든 기본 트랙 목록 이벤트를 트랙 목록으로 프록시
   * in은 해당 유형의 트랙 목록을 지원합니다.
   *
   * @사적인
   */
  프록시네이티브트랙_() {
    TRACK_TYPES.names.forEach((이름) => {
      this.proxyNativeTracksForType_(이름);
    });
  }

  /**
   * `Html5` Tech의 DOM 요소를 만듭니다.
   *
   * @return {요소}
   * 생성되는 요소.
   */
  createEl() {
    let el = this.options_.tag;

    // 이 브라우저가 요소를 상자로 이동하는 것을 지원하는지 확인합니다.
    // iPhone에서 요소를 이동하면 비디오가 깨집니다.
    // 따라서 새로운 요소를 만들어야 합니다.
    // 플레이어 div를 수집한 경우 미디어 요소를 이동할 필요가 없습니다.
    if (!엘 ||
        !(this.options_.playerElIngest ||
          this.movingMediaElementInDOM)) {

      // 원래 태그가 아직 있으면 복제하고 제거합니다.
      경우 (엘) {
        const 클론 = el.cloneNode(true);

        if (el.parentNode) {
          el.parentNode.insertBefore(클론, 엘);
        }
        Html5.disposeMediaElement(el);
        엘 = 클론;

      } else {
        el = document.createElement('동영상');

        // 네이티브 컨트롤을 사용해야 하는지 결정
        const tagAttributes = this.options_.tag && Dom.getAttributes(this.options_.tag);
        const 속성 = mergeOptions({}, tagAttributes);

        if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== 참) {
          속성을 삭제합니다.컨트롤;
        }

        Dom.setAttributes(
          엘자,
          할당(속성, {
            id: this.options_.techId,
            클래스: 'vjs-tech'
          })
        );
      }

      el.playerId = this.options_.playerId;
    }

    if (typeof this.options_.preload !== '정의되지 않음') {
      Dom.setAttribute(el, 'preload', this.options_.preload);
    }

    if (this.options_.disablePictureInPicture !== 정의되지 않음) {
      el.disablePictureInPicture = this.options_.disablePictureInPicture;
    }

    // 재정의된 경우 특정 태그 설정을 업데이트합니다.
    // `autoplay`는 *마지막*이어야 `muted` 및 `playsinline`이 존재합니다.
    // iOS/Safari 또는 기타 브라우저에서 자동 재생을 시도할 때.
    const settingsAttrs = ['loop', 'muted', 'playsinline', 'autoplay'];

    에 대한 (하자 i = 0; i < settingsAttrs.length; i++) {
      const attr = settingsAttrs[i];
      const 값 = this.options_[attr];

      if (값 유형 !== '정의되지 않음') {
        경우 (값) {
          Dom.setAttribute(el, attr, attr);
        } else {
          Dom.removeAttribute(el, attr);
        }
        el[attr] = 값;
      }
    }

    반환 엘;
  }

  /**
   * videojs가 실행되기 전에 loadstart 이벤트가 이미 발생한 경우 트리거됩니다.
   * 준비가 된. 이것이 발생할 수 있는 두 가지 알려진 예는 다음과 같습니다.
   * 1. 로드를 시작한 후 재생 개체를 로드하는 경우
   * 2. 미디어는 이미 (종종 자동 재생이 켜진 상태에서) 재생되고 있습니다.
   *
   * 이 함수는 videojs가 따라잡을 수 있도록 다른 loadstart를 실행합니다.
   *
   * @fires Tech#loadstart
   *
   * @return {정의되지 않음}
   * 아무것도 반환하지 않습니다.
   */
  handleLateInit_(el) {
    if (el.networkState === 0 || el.networkState === 3) {
      // 비디오 요소는 아직 소스 로드를 시작하지 않았습니다.
      // 소스를 찾지 못했거나
      반품;
    }

    경우 (el.readyState === 0) {
      // NetworkState는 동기식으로 설정되지만 loadstart는
      // 현재 스택의 끝, 일반적으로 setInterval(fn, 0) 이전.
      // 따라서 이 시점에서 우리는 loadstart가 이미 실행되었거나
      // 발사하려고 하고 어느 쪽이든 플레이어는 아직 그것을 보지 못했습니다.
      // 우리는 여기에서 loadstart를 조기에 시작하고 싶지 않습니다.
      // 로드 시작을 두 배로 하여 지금 사이에 발생하는지 확인합니다.
      // 그리고 다음 루프. 그렇지 않으면 실행합니다.
      // 하지만, loadmetadata 이전에 실행되는지 확인하고 싶습니다.
      // 현재와 다음 루프 사이에도 발생할 수 있으므로
      // 그것도 조심하세요.
      let loadstartFired = false;
      const setLoadstartFired = 함수() {
        loadstartFired = 참;
      };

      this.on('loadstart', setLoadstartFired);

      const triggerLoadstart = 함수() {
        // 원래 loadstart를 놓쳤습니다. 플레이어를 확인하십시오
        // loadedmetadata 전에 loadstart를 봅니다.
        if (!loadstartFired) {
          this.trigger('loadstart');
        }
      };

      this.on('loadedmetadata', triggerLoadstart);

      this.ready(함수() {
        this.off('loadstart', setLoadstartFired);
        this.off('loadedmetadata', triggerLoadstart);

        if (!loadstartFired) {
          // 원래 기본 로드 시작을 놓쳤습니다. 지금 발사하십시오.
          this.trigger('loadstart');
        }
      });

      반품;
    }

    // 여기에서 우리는 loadstart가 이미 시작되었고 우리가 그것을 놓쳤다는 것을 압니다.
    // 다른 readyState 이벤트는 두 배로 늘리면 큰 문제가 되지 않습니다.
    // 그것들을 방지하기 위해 loadstart만큼 많은 문제를 일으키지 않을 것입니다.
    // 우리가 이유를 찾지 않는 한.
    const eventsToTrigger = ['로드시작'];

    // loadedmetadata: 새롭게 HAVE_METADATA(1) 이상과 같음
    eventsToTrigger.push('loadedmetadata');

    // loadeddata: HAVE_CURRENT_DATA(2) 이상으로 새로 증가
    if (el.readyState > = 2) {
      eventsToTrigger.push('loadeddata');
    }

    // canplay: HAVE_FUTURE_DATA(3) 이상으로 새로 증가
    if (el.readyState > = 3) {
      eventsToTrigger.push('canplay');
    }

    // canplaythrough: 새로 HAVE_ENOUGH_DATA와 같음(4)
    if (el.readyState > = 4) {
      eventsToTrigger.push('canplaythrough');
    }

    // 여전히 플레이어에게 이벤트 리스너를 추가할 시간을 주어야 합니다.
    this.ready(함수() {
      eventsToTrigger.forEach(function(유형) {
        this.trigger(유형);
      }, 이것);
    });
  }

  /**
   * 스크러빙 여부를 설정합니다.
   * 이것은 `fastSeek`를 사용해야 하는지 여부를 결정하는 데 사용됩니다.
   * `fastSeek`은 Safari 브라우저에서 트릭 플레이를 제공하는 데 사용됩니다.
   *
   * @param {부울} isScrubbing
   * - 현재 스크러빙 중이므로 true
   * - 더 이상 스크러빙하지 않기 때문에 거짓
   */
  setScrubbing(isScrubbing) {
    this.isScrubbing_ = isScrubbing;
  }

  /**
   * 우리가 문지르고 있는지 여부를 확인하십시오.
   *
   * @return {부울} isScrubbing
   * - 현재 스크러빙 중이므로 true
   * - 더 이상 스크러빙하지 않기 때문에 거짓
   */
  스크러빙() {
    return this.isScrubbing_;
  }

  /**
   * `HTML5` 기술의 현재 시간을 설정합니다.
   *
   * @param {숫자}초
   * 미디어의 현재 시간을 이것으로 설정합니다.
   */
  setCurrentTime(초) {
    {
      if (this.isScrubbing_ && this.el_.fastSeek && 브라우저.IS_ANY_SAFARI) {
        this.el_.fastSeek(초);
      } else {
        this.el_.currentTime = 초;
      }
    } 잡기 (e) {
      log(e, '동영상이 준비되지 않았습니다. (Video.js)');
      // this.warning(VideoJS.warnings.videoNotReady);
    }
  }

  /**
   * HTML5 미디어 요소의 현재 재생 시간을 가져옵니다.
   *
   * @return {숫자}
   * 미디어의 길이 또는 길이가 없는 경우 0.
   */
  지속() {
    // Android Chrome은 이후까지 VOD HLS에 대한 기간을 무한대로 보고합니다.
    // 재생이 시작되어 라이브 디스플레이가 잘못 트리거됩니다.
    // 재생이 시작되지 않은 경우 NaN을 반환하고 기간 업데이트를 한 번 트리거합니다.
    // 기간을 확실하게 알 수 있습니다.
    만약에 (
      this.el_.duration === 무한대 &&
      브라우저.IS_ANDROID &&
      브라우저.IS_CHROME &&
      this.el_.currentTime === 0
    ) {
      // currentTime으로 첫 번째 `timeupdate` 대기 > 0 - 있을 수 있음
      // 0이 있는 여러 개
      const checkProgress = () => {
        if (this.el_.currentTime > 0) {
          // 진정한 라이브 비디오를 위한 기간 변경 트리거
          if (this.el_.duration === 무한대) {
            this.trigger('durationchange');
          }
          this.off('timeupdate', checkProgress);
        }
      };

      this.on('timeupdate', checkProgress);
      반환 NaN;
    }
    this.el_.duration을 반환 || NaN;
  }

  /**
   * HTML5 미디어 요소의 현재 너비를 가져옵니다.
   *
   * @return {숫자}
   * HTML5 미디어 요소의 너비입니다.
   */
  너비() {
    this.el_.offsetWidth 반환;
  }

  /**
   * HTML5 미디어 요소의 현재 높이를 가져옵니다.
   *
   * @return {숫자}
   * HTML5 미디어 요소의 높이입니다.
   */
  키() {
    this.el_.offsetHeight를 반환합니다.
  }

  /**
   * 프록시 iOS `webkitbeginfullscreen` 및 `webkitendfullscreen`을
   * `fullscreenchange` 이벤트.
   *
   * @사적인
   * @fires fullscreenchange
   * @listens webkitendfullscreen
   * @listens webkitbeginfullscreen
   * @listens webkitbeginfullscreen
   */
  프록시웹킷풀스크린_() {
    if (!('webkitDisplayingFullscreen' in this.el_)) {
      반품;
    }

    const endFn = 함수() {
      this.trigger('전체 화면 변경', { isFullscreen: false });
      // Safari는 기존 전체 화면일 때 videoelement에 컨트롤을 설정하는 경우가 있습니다.
      if (this.el_.controls && !this.options_.nativeControlsForTouch && this.controls()) {
        this.el_.controls = 거짓;
      }
    };

    const beginFn = 함수() {
      if (this.el_의 'webkitPresentationMode' && this.el_.webkitPresentationMode !== '픽처 인 픽처') {
        this.one('webkitendfullscreen', endFn);

        this.trigger('전체 화면 변경', {
          isFullscreen: 참,
          // 다른 기술이 전체 화면 변경을 트리거하는 경우 플래그를 설정합니다.
          NativeIOSFullscreen: true
        });
      }
    };

    this.on('webkitbeginfullscreen', beginFn);
    this.on('처리', () => {
      this.off('webkitbeginfullscreen', beginFn);
      this.off('webkitendfullscreen', endFn);
    });
  }

  /**
   * 현재 재생 장치에서 전체 화면을 지원하는지 확인하십시오.
   *
   * @return {부울}
   * - 전체 화면이 지원되는 경우 True입니다.
   * - 전체 화면이 지원되지 않는 경우 False입니다.
   */
  supportFullScreen() {
    if (typeof this.el_.webkitEnterFullScreen === '함수') {
      const userAgent = window.navigator && window.navigator.userAgent || '';

      // Chromium/Chrome에서 깨진 것 같습니다. && 표범의 사파리
      if ((/Android/).test(userAgent) || !(/Chrome|Mac OS X 10.5/).test(userAgent)) {
        true를 반환합니다.
      }
    }
    거짓을 반환합니다.
  }

  /**
   * `HTML5` 기술이 전체 화면으로 전환되도록 요청하십시오.
   */
  enterFullScreen() {
    const 비디오 = this.el_;

    if (동영상.일시중지 && video.networkState < = 동영상.HAVE_METADATA) {
      // 프로그래밍 방식 액세스를 위해 비디오 요소를 초기화하려고 시도합니다.
      // 이것은 데스크톱에서는 필요하지 않지만 다치게 해서는 안 됩니다.
      침묵 약속(this.el_.play());

      // 전체 화면으로 전환하는 동안 동시에 재생 및 일시 중지
      // iOS ~6.1 장치를 재생/일시 정지 루프로 가져올 수 있습니다.
      this.setTimeout(함수() {
        video.pause();
        {
          video.webkitEnterFullScreen();
        } 잡기 (e) {
          this.trigger('전체 화면 오류', e);
        }
      }, 0);
    } else {
      {
        video.webkitEnterFullScreen();
      } 잡기 (e) {
        this.trigger('전체 화면 오류', e);
      }
    }
  }

  /**
   * `HTML5` 기술이 전체 화면을 종료하도록 요청하십시오.
   */
  exitFullScreen() {
    if (!this.el_.webkitDisplayingFullscreen) {
      this.trigger('fullscreenerror', new Error('동영상이 전체화면이 아닙니다.'));
      반품;
    }

    this.el_.webkitExitFullScreen();
  }

  /**
   * 플로팅 비디오 창을 항상 다른 창 위에 생성하여 사용자가
   * 다른 콘텐츠 사이트와 상호 작용하는 동안 미디어를 계속 소비하거나
   * 기기의 애플리케이션.
   *
   * @see [사양]{@link https://wicg.github.io/picture-in-picture}
   *
   * @return {약속}
   * Picture-in-Picture 창과의 약속.
   */
  requestPictureInPicture() {
    return this.el_.requestPictureInPicture();
  }

  /**
   * 브라우저/기술 또는 폴백에서 지원하는 경우 기본 requestVideoFrameCallback
   * DRM이 실행 중일 때 Safari에서 rVCF를 사용하지 마십시오. 실행되지 않습니다.
   * 생성자 이후에 확인 필요
   * 이는 Fairplay 소스 이후에 로드된 명확한 소스에 대해 거짓 긍정이 됩니다.
   *
   * @param {function} 호출할 cb 함수
   * @return {숫자} 요청 ID
   */
  requestVideoFrameCallback(cb) {
    if (이.featuresVideoFrameCallback && !this.el_.webkitKeys) {
      return this.el_.requestVideoFrameCallback(cb);
    }
    return super.requestVideoFrameCallback(cb);
  }

  /**
   * 기본 또는 대체 requestVideoFrameCallback
   *
   * @param {number} id 취소할 요청 ID
   */
  cancelVideoFrameCallback(id) {
    if (이.featuresVideoFrameCallback && !this.el_.webkitKeys) {
      this.el_.cancelVideoFrameCallback(id);
    } else {
      super.cancelVideoFrameCallback(id);
    }
  }

  /**
   * `Html5` Tech의 소스 개체에 대한 getter/setter입니다.
   * > 메모: {@link Html5#setSource}를 사용하세요.
   *
   * @param {Tech~SourceObject} [소스]
   * `HTML5` techs 요소에 설정하려는 소스 개체입니다.
   *
   * @return {Tech~SourceObject|정의되지 않음}
   * - 소스가 전달되지 않은 경우 현재 소스 개체입니다.
   * - 설정 시 정의되지 않음
   *
   * @deprecated 버전 5부터.
   */
  소스(소스) {
    if (src === 정의되지 않음) {
      this.el_.src를 반환합니다.
    }

    // `setSrc` 대신 `src`를 통해 src를 설정하는 것은 더 이상 사용되지 않습니다.
    this.setSrc(src);
  }

  /**
   * 모든 소스를 제거한 다음 전화하여 기술을 재설정하십시오.
   * {@link Html5.resetMediaElement}.
   */
  초기화() {
    Html5.resetMediaElement(this.el_);
  }

  /**
   * `HTML5` Tech에서 현재 소스를 받으세요. 다음에서 소스를 반환하도록 폴백합니다.
   * HTML5 미디어 요소.
   *
   * @return {기술~소스 객체}
   * HTML5 기술의 현재 소스 개체입니다. 다음으로 대체
   * 요소 소스.
   */
  currentSrc() {
    if (이.currentSource_) {
      this.currentSource_.src를 반환합니다.
    }
    this.el_.currentSrc를 반환합니다.
  }

  /**
   * HTML5 미디어 요소에 대한 컨트롤 속성을 설정합니다.
   *
   * @param {문자열} 값
   * controls 속성을 설정할 값
   */
  setControls(값) {
    this.el_.controls = !!발;
  }

  /**
   * 원격 {@link TextTrack} 객체를 생성하고 반환합니다.
   *
   * @param {문자열} 종류
   * `TextTrack` 종류(자막, 캡션, 설명, 챕터 또는 메타데이터)
   *
   * @param {문자열} [레이블]
   * 텍스트 트랙을 식별하는 레이블
   *
   * @param {문자열} [언어]
   * 두 글자 언어 약어
   *
   * @return {텍스트 트랙}
   * 생성되는 TextTrack.
   */
  addTextTrack(종류, 라벨, 언어) {
    if (!this.featuresNativeTextTracks) {
      return super.addTextTrack(종류, 라벨, 언어);
    }

    return this.el_.addTextTrack(종류, 라벨, 언어);
  }

  /**
   * 기본 TextTrack 또는 에뮬레이트된 TextTrack을 생성합니다.
   * `featuresNativeTextTracks` 값에 대해
   *
   * @param {객체} 옵션
   * 객체는 TextTrack을 초기화하는 옵션을 포함해야 합니다.
   *
   * @param {문자열} [옵션.종류]
   * `TextTrack` 종류(자막, 캡션, 설명, 챕터 또는 메타데이터).
   *
   * @param {문자열} [옵션.레이블]
   * 텍스트 트랙을 식별하는 레이블
   *
   * @param {문자열} [옵션.언어]
   * 두 글자 언어 약어.
   *
   * @param {부울} [옵션.기본값]
   * 이 트랙을 켜짐으로 기본 설정합니다.
   *
   * @param {문자열} [옵션.ID]
   * 이 트랙을 할당할 내부 ID입니다.
   *
   * @param {문자열} [옵션.src]
   * 트랙의 소스 URL.
   *
   * @return {HTMLTrackElement}
   * 생성되는 트랙 요소.
   */
  createRemoteTextTrack(옵션) {
    if (!this.featuresNativeTextTracks) {
      return super.createRemoteTextTrack(옵션);
    }
    const htmlTrackElement = document.createElement('트랙');

    if (옵션.종류) {
      htmlTrackElement.kind = 옵션.종류;
    }
    if (옵션.레이블) {
      htmlTrackElement.label = 옵션.레이블;
    }
    if (옵션.언어 || 옵션.srclang) {
      htmlTrackElement.srclang = 옵션.언어 || options.srclang;
    }
    경우 (옵션.기본값) {
      htmlTrackElement.default = 옵션.기본;
    }
    경우 (옵션.ID) {
      htmlTrackElement.id = options.id;
    }
    경우 (옵션.src) {
      htmlTrackElement.src = options.src;
    }

    htmlTrackElement 반환;
  }

  /**
   * 원격 텍스트 추적 개체를 만들고 html 추적 요소를 반환합니다.
   *
   * @param {Object} options 객체는 다음에 대한 값을 포함해야 합니다.
   * 종류, 언어, 레이블 및 src(WebVTT 파일 위치)
   * @param {boolean} [manualCleanup=true] false로 설정하면 TextTrack은
   * 소스가 변경될 때마다 비디오 요소에서 자동으로 제거됨
   * @return {HTMLTrackElement} HTML 트랙 요소.
   * 이것은 에뮬레이트된 {@link HTMLTrackElement} 또는 네이티브 것일 수 있습니다.
   * @deprecated "manualCleanup" 매개변수의 기본값은 기본값이 됩니다.
   * 향후 버전의 Video.js에서 "false"로 변경
   */
  addRemoteTextTrack(옵션, manualCleanup) {
    const htmlTrackElement = super.addRemoteTextTrack(옵션, manualCleanup);

    if (this.featuresNativeTextTracks) {
      this.el().appendChild(htmlTrackElement);
    }

    htmlTrackElement 반환;
  }

  /**
   * `TextTrackList` 개체에서 원격 `TextTrack` 제거
   *
   * @param {TextTrack} 트랙
   * 제거할 `TextTrack` 개체
   */
  removeRemoteTextTrack(트랙) {
    super.removeRemoteTextTrack(트랙);

    if (this.featuresNativeTextTracks) {
      const 트랙 = this.$$('트랙');

      let i = 트랙 길이;

      동안 (i--) {
        if (트랙 === 트랙[i] || 트랙 === 트랙[i].트랙) {
          this.el().removeChild(tracks[i]);
        }
      }
    }
  }

  /**
   * W3C의 미디어에서 지정한 대로 사용 가능한 미디어 재생 품질 메트릭을 가져옵니다.
   * 재생 품질 API.
   *
   * @see [사양]{@link https://wicg.github.io/media-playback-quality}
   *
   * @return {객체}
   * 지원되는 미디어 재생 품질 메트릭이 있는 개체
   */
  getVideoPlaybackQuality() {
    if (typeof this.el().getVideoPlaybackQuality === '함수') {
      return this.el().getVideoPlaybackQuality();
    }

    const videoPlaybackQuality = {};

    if (typeof this.el().webkitDroppedFrameCount !== '정의되지 않음' &&
        typeof this.el().webkitDecodedFrameCount !== '정의되지 않음') {
      videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount;
      videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount;
    }

    if (창.성능 && typeof window.performance.now === '함수') {
      videoPlaybackQuality.creationTime = window.performance.now();
    } 그렇지 않으면 (window.performance &&
               창.성능.타이밍 &&
               typeof window.performance.timing.navigationStart === '숫자') {
      videoPlaybackQuality.creationTime =
        window.Date.now() - window.performance.timing.navigationStart;
    }

    videoPlaybackQuality 반환;
  }
}

/* HTML5 지원 테스트 --------------------------------------------- ------- */

/**
 * 브라우저 HTML5 미디어 기능을 테스트하기 위한 요소
 *
 * @type {요소}
 * @끊임없는
 * @사적인
 */
defineLazyProperty(Html5, 'TEST_VID', function() {
  if (!Dom.isReal()) {
    반품;
  }
  const video = document.createElement('비디오');
  const 트랙 = document.createElement('트랙');

  track.kind = '캡션';
  track.srclang = 'en';
  track.label = '영어';
  video.appendChild(트랙);

  비디오 반환;
});

/**
 * 이 브라우저/장치에서 HTML5 미디어를 지원하는지 확인하십시오.
 *
 * @return {부울}
 * - HTML5 미디어가 지원되는 경우 True입니다.
 * - HTML5 미디어가 지원되지 않는 경우 False입니다.
 */
Html5.isSupported = 함수() {
  // 미디어 플레이어가 없는 IE는 거짓말쟁이입니다! (#984)
  {
    Html5.TEST_VID.volume = 0.5;
  } 잡기 (e) {
    거짓을 반환합니다.
  }

  반환!!(Html5.TEST_VID && Html5.TEST_VID.canPlayType);
};

/**
 * 기술이 주어진 유형을 지원할 수 있는지 확인
 *
 * @param {문자열} 유형
 * 확인할 mimetype
 * @return {string} 'probably', 'maybe' 또는 '' (빈 문자열)
 */
Html5.canPlayType = 함수(유형) {
  return Html5.TEST_VID.canPlayType(유형);
};

/**
 * 기술이 주어진 소스를 지원할 수 있는지 확인
 *
 * @param {객체} srcObj
 * 소스 객체
 * @param {객체} 옵션
 * 기술자에게 전달된 옵션
 * @return {string} 'probably', 'maybe' 또는 '' (빈 문자열)
 */
Html5.canPlaySource = function(srcObj, 옵션) {
  return Html5.canPlayType(srcObj.type);
};

/**
 * 이 브라우저/장치에서 볼륨을 변경할 수 있는지 확인하십시오.
 * 많은 모바일 장치에서 볼륨을 변경할 수 없습니다.
 * 특히 iOS에서는 1에서 변경할 수 없습니다.
 *
 * @return {부울}
 * - 볼륨을 제어할 수 있는 경우 True
 * - 그렇지 않으면 거짓
 */
Html5.canControlVolume = 함수() {
  // Windows Media Player가 설치되지 않은 경우 IE에서 오류가 발생합니다. #3315
  {
    const 볼륨 = Html5.TEST_VID.volume;

    Html5.TEST_VID.volume = (볼륨 / 2) + 0.1;

    const canControl = 볼륨 !== Html5.TEST_VID.volume;

    // iOS 15 도입으로 볼륨을 다음과 같이 읽는 경우가 있습니다.
    // 변경되었지만 다음 틱 시작 시 원래 상태로 되돌아갑니다.
    // iOS에서 볼륨 조절이 가능한지 확인하려면,
    // 시간 초과가 설정되고 볼륨이 비동기적으로 확인됩니다.
    // `features`는 현재 비동기식으로 작동하지 않으므로 값을 수동으로 설정합니다.
    if (canControl && 브라우저.IS_IOS) {
      window.setTimeout(() => {
        만약 (HTML5 && HTML5.프로토타입) {
          Html5.prototype.featuresVolumeControl = 볼륨 !== Html5.TEST_VID.volume;
        }
      });

      // 기본 iOS는 false로, 위의 시간 제한에서 업데이트됩니다.
      거짓을 반환합니다.
    }

    canControl을 반환합니다.
  } 잡기 (e) {
    거짓을 반환합니다.
  }
};

/**
 * 이 브라우저/장치에서 볼륨을 음소거할 수 있는지 확인하십시오.
 * 일부 기기(예: iOS)는 볼륨 변경을 허용하지 않습니다.
 * 그러나 음소거/음소거 해제는 허용합니다.
 *
 * @return {볼린}
 * - 볼륨을 음소거할 수 있는 경우 True
 * - 그렇지 않으면 거짓
 */
Html5.canMuteVolume = 함수() {
  {
    const muted = Html5.TEST_VID.muted;

    // iOS의 일부 버전에서는 muted 속성이 항상 그렇지는 않습니다.
    // 작동하므로 속성과 속성을 모두 설정해야 합니다.
    Html5.TEST_VID.muted = !음소거;
    if (Html5.TEST_VID.muted) {
      Dom.setAttribute(Html5.TEST_VID, '음소거됨', '음소거됨');
    } else {
      Dom.removeAttribute(Html5.TEST_VID, '음소거됨', '음소거됨');
    }
    음소거 반환 !== Html5.TEST_VID.muted;
  } 잡기 (e) {
    거짓을 반환합니다.
  }
};

/**
 * 이 브라우저/장치에서 재생 속도를 변경할 수 있는지 확인하십시오.
 *
 * @return {부울}
 * - 재생 속도를 제어할 수 있는 경우 True
 * - 그렇지 않으면 거짓
 */
Html5.canControlPlaybackRate = 함수() {
  // Playback rate API는 Android Chrome에 구현되어 있지만 아무것도 하지 않음
  // https://github.com/videojs/video.js/issues/3180
  경우 (browser.IS_ANDROID && 브라우저.IS_CHROME && 브라우저.CHROME_VERSION < 58) {
    거짓을 반환합니다.
  }
  // Windows Media Player가 설치되지 않은 경우 IE에서 오류가 발생합니다. #3315
  {
    const playbackRate = Html5.TEST_VID.playbackRate;

    Html5.TEST_VID.playbackRate = (재생 속도 / 2) + 0.1;
    return playbackRate !== Html5.TEST_VID.playbackRate;
  } 잡기 (e) {
    거짓을 반환합니다.
  }
};

/**
 * 비디오/오디오 요소 속성을 무시할 수 있는지 확인하십시오.
 * Object.defineProperty.
 *
 * @return {부울}
 * - 내장 속성을 재정의할 수 있는 경우 True
 * - 그렇지 않으면 거짓
 */
Html5.canOverrideAttributes = 함수() {
  // src/innerHTML 속성을 덮어쓸 수 없으면 지원되지 않습니다.
  // 예를 들어 iOS 7 사파리는 이것을 할 수 없습니다.
  {
    const noop = () => {};

    Object.defineProperty(document.createElement('비디오'), 'src', {get: noop, set: noop});
    Object.defineProperty(document.createElement('audio'), 'src', {get: noop, set: noop});
    Object.defineProperty(document.createElement('video'), 'innerHTML', {get: noop, set: noop});
    Object.defineProperty(document.createElement('audio'), 'innerHTML', {get: noop, set: noop});
  } 잡기 (e) {
    거짓을 반환합니다.
  }

  true를 반환합니다.
};

/**
 * 기본 `TextTrack`이 이 브라우저/장치에서 지원되는지 확인하십시오.
 *
 * @return {부울}
 * - 기본 `TextTrack`이 지원되는 경우 True입니다.
 * - 그렇지 않으면 거짓
 */
Html5.supportsNativeTextTracks = 함수() {
  브라우저 반환.IS_ANY_SAFARI || (브라우저.IS_IOS && 브라우저.IS_CHROME);
};

/**
 * 기본 `VideoTrack`이 이 브라우저/장치에서 지원되는지 확인하십시오.
 *
 * @return {부울}
 * - 기본 `VideoTrack`이 지원되는 경우 True입니다.
 * - 그렇지 않으면 거짓
 */
Html5.supportsNativeVideoTracks = 함수() {
  반환!!(Html5.TEST_VID && Html5.TEST_VID.videoTracks);
};

/**
 * 이 브라우저/장치에서 기본 `AudioTrack`이 지원되는지 확인하십시오.
 *
 * @return {부울}
 * - 네이티브 `AudioTrack`이 지원되는 경우 True입니다.
 * - 그렇지 않으면 거짓
 */
Html5.supportsNativeAudioTracks = 함수() {
  반환!!(Html5.TEST_VID && Html5.TEST_VID.audioTracks);
};

/**
 * Html5 기술에서 사용할 수 있는 다양한 이벤트.
 *
 * @사적인
 * @type {배열}
 */
Html5.이벤트 = [
  '로드스타트',
  '유예하다',
  '중단',
  '오류',
  '비워지다',
  '정지',
  '로드된 메타데이터',
  '로드데이터',
  '놀 수있다',
  'canplaythrough',
  '놀이',
  '대기 중',
  '찾다',
  '찾았다',
  '종료',
  '기간 변경',
  '시간 업데이트',
  '진전',
  '놀다',
  '정지시키다',
  '요금 변경',
  '크기 조정',
  '볼륨체인지'
];

/**
 * `Tech`가 볼륨 조절을 지원하는지 여부를 나타내는 부울입니다.
 *
 * @유형 {부울}
 * @default {@link Html5.canControlVolume}
 */
/**
 * `Tech`가 음소거 볼륨을 지원하는지 여부를 나타내는 부울입니다.
 *
 * @type {볼린}
 * @default {@link Html5.canMuteVolume}
 */

/**
 * 'Tech'가 미디어의 속도 변경을 지원하는지 여부를 나타내는 부울
 * 연극. 예:
 * - 플레이어가 2배(2배) 빠르게 플레이하도록 설정
 * - 플레이어가 0.5배(절반) 빠르게 플레이하도록 설정
 *
 * @유형 {부울}
 * @default {@link Html5.canControlPlaybackRate}
 */

/**
 * `Tech`가 `sourceset` 이벤트를 지원하는지 여부를 나타내는 부울입니다.
 *
 * @유형 {부울}
 * @기본
 */
/**
 * `HTML5` 기술이 현재 기본 `TextTrack`을 지원하는지 여부를 나타내는 부울입니다.
 *
 * @유형 {부울}
 * @default {@link Html5.supportsNativeTextTracks}
 */
/**
 * `HTML5` 기술이 현재 기본 `VideoTrack`을 지원하는지 여부를 나타내는 부울입니다.
 *
 * @유형 {부울}
 * @default {@link Html5.supportsNativeVideoTracks}
 */
/**
 * `HTML5` 기술이 현재 기본 `AudioTrack`을 지원하는지 여부를 나타내는 부울입니다.
 *
 * @유형 {부울}
 * @default {@link Html5.supportsNativeAudioTracks}
 */
[
  ['featuresMuteControl', 'canMuteVolume'],
  ['featuresPlaybackRate', 'canControlPlaybackRate'],
  ['featuresSourceset', 'canOverrideAttributes'],
  ['featuresNativeTextTracks', 'supportsNativeTextTracks'],
  ['기능NativeVideoTracks', 'supportsNativeVideoTracks'],
  ['기능NativeAudioTracks', 'supportsNativeAudioTracks']
].forEach(함수([키, fn]) {
  defineLazyProperty(Html5.prototype, 키, () => Html5[fn](), 참);
});

Html5.prototype.featuresVolumeControl = Html5.canControlVolume();

/**
 * `HTML5` 기술이 현재 미디어 요소를 지원하는지 여부를 나타내는 부울
 * DOM에서 이동. 미디어 요소를 이동하면 iOS가 중단되므로 다음과 같이 설정합니다.
 * 거기에 거짓. 다른 곳에서는 이것이 사실이어야 합니다.
 *
 * @유형 {부울}
 * @기본
 */
Html5.prototype.movingMediaElementInDOM = !browser.IS_IOS;

// 할 것: 이전 댓글: 더 이상 사용되지 않는 것 같습니다. 제거할 수 있습니다.
// 사실인가요?
/**
 * `HTML5` 기술이 현재 자동 미디어 크기 조정을 지원하는지 여부를 나타내는 부울
 * 전체 화면으로 전환할 때.
 *
 * @유형 {부울}
 * @기본
 */
Html5.prototype.featuresFullscreenResize = 참;

/**
 * `HTML5` 기술이 현재 진행 이벤트를 지원하는지 여부를 나타내는 부울입니다.
 * 이것이 거짓이면 수동 `progress` 이벤트가 대신 트리거됩니다.
 *
 * @유형 {부울}
 * @기본
 */
Html5.prototype.featuresProgressEvents = 참;

/**
 * `HTML5` 기술이 현재 timeupdate 이벤트를 지원하는지 여부를 나타내는 부울입니다.
 * 이것이 거짓이면 수동 `timeupdate` 이벤트가 대신 트리거됩니다.
 *
 * @기본
 */
Html5.prototype.featuresTimeupdateEvents = 참;

/**
 * HTML5 엘이 `requestVideoFrameCallback`을 지원하는지 여부
 *
 * @유형 {부울}
 */
Html5.prototype.featuresVideoFrameCallback = !!(Html5.TEST_VID && Html5.TEST_VID.requestVideoFrameCallback);

// HTML5 기능 감지 및 장치 수정 ---------------------------------- //
canPlayType하자;

Html5.patchCanPlayType = 함수() {

  // Android 4.0 이상은 HLS를 어느 정도 재생할 수 있지만 그렇게 할 수 없다고 보고합니다.
  // Firefox 및 Chrome이 올바르게 보고합니다.
  if (브라우저.ANDROID_VERSION > = 4.0 && !browser.IS_FIREFOX && !브라우저.IS_CHROME) {
    canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType;
    Html5.TEST_VID.constructor.prototype.canPlayType = 함수(유형) {
      const mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i;

      만약 (유형 && mpegurlRE.test(유형)) {
        '어쩌면'을 반환합니다.
      }
      return canPlayType.call(this, type);
    };
  }
};

Html5.unpatchCanPlayType = 함수() {
  const r = Html5.TEST_VID.constructor.prototype.canPlayType;

  경우 (canPlayType) {
    Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
  }
  반환 r;
};

// 기본적으로 미디어 요소를 패치합니다.
Html5.patchCanPlayType();

Html5.disposeMediaElement = 함수(엘) {
  경우 (!엘) {
    반품;
  }

  if (el.parentNode) {
    el.parentNode.removeChild(el);
  }

  // 로드를 방지하기 위해 하위 트랙 또는 소스 노드를 제거합니다.
  동안 (el.hasChildNodes()) {
    el.removeChild(el.firstChild);
  }

  // src 참조를 제거합니다. 경고가 발생하므로 `src=''`를 설정하지 않습니다.
  // 파이어폭스에서
  el.removeAttribute('src');

  // load()를 호출하여 미디어 요소가 로드 상태를 업데이트하도록 합니다.
  // 그러나 Windows 7N의 IE에는 오류가 발생하는 버그가 있으므로 try/catch가 필요합니다(#793).
  if (typeof el.load === '함수') {
    // 최적화되지 않도록 iife에 래핑(#1060#discussion_r10324473)
    (기능() {
      {
        엘.로드();
      } 잡기 (e) {
        // 지원되지 않음
      }
    }());
  }
};

Html5.resetMediaElement = 함수(엘) {
  경우 (!엘) {
    반품;
  }

  const sources = el.querySelectorAll('source');
  let i = 소스.길이;

  동안 (i--) {
    el.removeChild(소스[i]);
  }

  // src 참조를 제거합니다.
  // 오류가 발생하므로 `src=''`를 설정하지 않습니다.
  el.removeAttribute('src');

  if (typeof el.load === '함수') {
    // 최적화되지 않도록 iife에 래핑(#1060#discussion_r10324473)
    (기능() {
      {
        엘.로드();
      } 잡기 (e) {
        // 린터 만족
      }
    }());
  }
};

/* 기본 HTML5 요소 속성 래핑 -------------------------------------------------- */
// 속성과 속성을 모두 확인하는 게터로 기본 부울 속성을 래핑합니다.
// 목록은 다음과 같습니다.
// 음소거, defaultMuted, autoplay, controls, loop, playsinline
[
  /**
   * 미디어 요소에서 `muted` 값을 가져옵니다. '음소거됨'은 다음을 나타냅니다.
   * 미디어 볼륨을 무음으로 설정해야 합니다. 이것은 실제로 변경되지 않습니다
   * `volume` 속성.
   *
   * @method Html5#muted
   * @return {부울}
   * - '볼륨' 값을 무시하고 오디오를 무음으로 설정해야 하는 경우 참입니다.
   * - `볼륨` 값을 사용해야 하는 경우 거짓입니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
   */
  '음소거',

  /**
   * 미디어 요소에서 `defaultMute` 값을 가져옵니다. `defaultMuted`는 다음을 나타냅니다.
   * 미디어가 음소거 상태로 시작되어야 하는지 여부. 의 기본 상태만 변경합니다.
   * 미디어. `muted` 및 `defaultMuted`는 다른 값을 가질 수 있습니다. {@link Html5#muted}는
   * 현재 상태.
   *
   * @method Html5#defaultMuted
   * @return {부울}
   * - 미디어 요소의 `defaultMuted` 값입니다.
   * - True는 미디어가 음소거 상태로 시작되어야 함을 나타냅니다.
   * - False는 미디어가 음소거 상태로 시작되지 않아야 함을 나타냅니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
   */
  '기본 음소거됨',

  /**
   * 미디어 요소에서 `autoplay` 값을 가져옵니다. '자동재생'은 다음을 나타냅니다.
   * 페이지가 준비되자마자 미디어 재생을 시작해야 합니다.
   *
   * @method Html5#autoplay
   * @return {부울}
   * - 미디어 요소의 `autoplay` 값입니다.
   * - True는 페이지가 로드되자마자 미디어가 시작되어야 함을 나타냅니다.
   * - False는 페이지가 로드되자마자 미디어가 시작되지 않아야 함을 나타냅니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
   */
  '자동 재생',

  /**
   * 미디어 요소에서 `controls` 값을 가져옵니다. '컨트롤'은 다음을 나타냅니다.
   * 기본 미디어 컨트롤을 표시할지 숨길지 여부.
   *
   * @method Html5#controls
   * @return {부울}
   * - 미디어 요소의 `controls` 값입니다.
   * - True는 네이티브 컨트롤이 표시되어야 함을 나타냅니다.
   * - False는 네이티브 컨트롤을 숨겨야 함을 나타냅니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls}
   */
  '통제 수단',

  /**
   * 미디어 요소에서 `loop` 값을 가져옵니다. 루프'는 다음을 나타냅니다.
   * 미디어가 미디어의 시작 부분으로 돌아가서 한 번 계속 재생해야 함
   * 끝까지 갑니다.
   *
   * @method Html5#loop
   * @return {부울}
   * - 미디어 요소의 `loop` 값입니다.
   * - True는 재생이 한 번 시작하기 위해 뒤로 탐색해야 함을 나타냅니다.
   * 미디어의 끝에 도달했습니다.
   * - False는 재생이 시작 부분으로 돌아가지 않아야 함을 나타냅니다.
   * 미디어 끝에 도달했습니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
   */
  '고리',

  /**
   * 미디어 요소에서 `playsinline` 값을 가져옵니다. `playsinline`은 다음을 나타냅니다.
   * 전체 화면일 때 전체 화면이 아닌 재생이 선호되는 브라우저에
   * 재생은 iOS Safari와 같은 기본 기본값입니다.
   *
   * @method Html5#playsinline
   * @return {부울}
   * - 미디어 요소의 `playsinline` 값입니다.
   * - True는 미디어가 인라인으로 재생되어야 함을 나타냅니다.
   * - False는 미디어가 인라인으로 재생되지 않아야 함을 나타냅니다.
   *
   * @see [사양]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
   */
  '플레이인라인'
].forEach(함수(소품) {
  Html5.prototype[prop] = 함수() {
    return this.el_[소품] || this.el_.hasAttribute(prop);
  };
});

// 속성과 속성을 모두 설정하는 setter로 기본 부울 속성을 래핑합니다.
// 목록은 다음과 같습니다.
// setMuted, setDefaultMuted, setAutoplay, setLoop, setPlaysinline
// setControls는 위의 특별한 경우입니다.
[
  /**
   * 미디어 요소에 `음소거` 값을 설정합니다. '음소거됨'은 현재
   * 오디오 레벨은 조용해야 합니다.
   *
   * @method Html5#setMuted
   * @param {부울} 음소거됨
   * - 오디오를 무음으로 설정해야 하는 경우 True
   * - 그렇지 않으면 거짓
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
   */
  '음소거',

  /**
   * 미디어 요소에 `defaultMute` 값을 설정합니다. `defaultMuted`는 현재
   * 오디오 레벨은 조용해야 하지만 처음 재생 시 음소거된 레벨에만 영향을 미칩니다.
   *
   * @method Html5.prototype.setDefaultMuted
   * @param {부울} defaultMuted
   * - 오디오를 무음으로 설정해야 하는 경우 True
   * - 그렇지 않으면 거짓
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
   */
  '기본 음소거됨',

  /**
   * 미디어 요소에 `autoplay` 값을 설정합니다. '자동재생'은 다음을 나타냅니다.
   * 페이지가 준비되자마자 미디어 재생을 시작해야 합니다.
   *
   * @method Html5#setAutoplay
   * @param {boolean} 자동 재생
   * - True는 페이지가 로드되자마자 미디어가 시작되어야 함을 나타냅니다.
   * - False는 페이지가 로드되자마자 미디어가 시작되지 않아야 함을 나타냅니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
   */
  '자동 재생',

  /**
   * 미디어 요소에 `loop` 값을 설정합니다. '루프'는 다음을 나타냅니다.
   * 미디어가 미디어의 시작 부분으로 돌아가서 한 번 계속 재생해야 함
   * 끝까지 갑니다.
   *
   * @method Html5#setLoop
   * @param {부울} 루프
   * - True는 재생이 한 번 시작하기 위해 뒤로 탐색해야 함을 나타냅니다.
   * 미디어의 끝에 도달했습니다.
   * - False는 재생이 시작 부분으로 돌아가지 않아야 함을 나타냅니다.
   * 미디어 끝에 도달했습니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
   */
  '고리',

  /**
   * 미디어 요소에서 `playsinline` 값을 설정합니다. `playsinline`은 다음을 나타냅니다.
   * 전체 화면일 때 전체 화면이 아닌 재생이 선호되는 브라우저에
   * 재생은 iOS Safari와 같은 기본 기본값입니다.
   *
   * @method Html5#setPlaysinline
   * @param {boolean} 재생인라인
   * - True는 미디어가 인라인으로 재생되어야 함을 나타냅니다.
   * - False는 미디어가 인라인으로 재생되지 않아야 함을 나타냅니다.
   *
   * @see [사양]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
   */
  '플레이인라인'
].forEach(함수(소품) {
  Html5.prototype['set' + toTitleCase(prop)] = function(v) {
    this.el_[prop] = v;

    만약 (v) {
      this.el_.setAttribute(소품, 소품);
    } else {
      this.el_.removeAttribute(prop);
    }
  };
});

// 기본 속성을 getter로 래핑합니다.
// 목록은 다음과 같습니다.
// 일시 중지됨, 현재 시간, 버퍼링됨, 볼륨, 포스터, 사전 로드, 오류, 탐색
// 탐색 가능, 종료됨, playbackRate, defaultPlaybackRate, disablePictureInPicture
// 재생됨, networkState, readyState, videoWidth, videoHeight, crossOrigin
[
  /**
   * 미디어 요소에서 `paused` 값을 가져옵니다. 'paused'는 미디어 요소가
   * 현재 일시정지 여부입니다.
   *
   * @method Html5#paused
   * @return {부울}
   * 미디어 요소의 `paused` 값입니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused}
   */
  '일시중지',

  /**
   * 미디어 요소에서 `currentTime` 값을 가져옵니다. `currentTime`은 다음을 나타냅니다.
   * 미디어가 재생 중인 현재 초.
   *
   * @method Html5#currentTime
   * @return {숫자}
   * 미디어 요소의 `currentTime` 값입니다.
   *
   * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime}
   */
  '현재 시간',

  /**
   * 미디어 요소에서 `buffered` 값을 가져옵니다. `buffered`는 `TimeRange`입니다.
   * 이미 다운로드된 미디어 부분을 나타내는 개체 및
   * 재생이 가능합니다.
   *
   * @method Html5#buffered
   * @return {시간 범위}
   * 미디어 요소의 `buffered` 값입니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered}
   */
  '버퍼',

  /**
   * 미디어 요소에서 `볼륨` 값을 가져옵니다. '볼륨' 표시
   * 미디어에 대한 오디오의 현재 재생 볼륨. `볼륨`은 0부터의 값입니다.
   *(무음)에서 1(가장 시끄럽고 기본값).
   *
   * @method Html5#볼륨
   * @return {숫자}
   * 미디어 요소의 `볼륨` 값입니다. 값은 0-1 사이입니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
   */
  '용량',

  /**
   * 미디어 요소에서 `poster` 값을 가져옵니다. '포스터'는 다음을 나타냅니다.
   * 사용 가능한 미디어 데이터가 없을 때 표시될 수 있는/표시될 이미지 파일의 URL입니다.
   *
   * @method Html5#포스터
   * @return {문자열}
   * 미디어 요소의 `poster` 값입니다. 값은
   * 이미지.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster}
   */
  '포스터',

  /**
   * 미디어 요소에서 `preload` 값을 가져옵니다. '예압'은 다음을 나타냅니다.
   * 미디어가 상호 작용하기 전에 다운로드해야 하는 항목. 그것은 다음을 가질 수 있습니다
   * 값:
   * - 없음: 아무것도 다운로드하지 않아야 합니다.
   * - 메타데이터: 포스터와 미디어의 처음 몇 프레임을 다운로드하여 얻을 수 있습니다.
   * 미디어 크기 및 기타 메타데이터
   * - auto: 미디어 및 미디어에 대한 메타데이터가 이전에 다운로드되도록 허용
   * 상호 작용
   *
   * @method Html5#preload
   * @return {문자열}
   * 미디어 요소의 `preload` 값입니다. '없음', '메타데이터',
   * 또는 '자동'.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
   */
  '예압',

  /**
   * 미디어 요소에서 `error` 값을 가져옵니다. `오류`는
   * 재생 중에 발생할 수 있는 MediaError입니다. 오류가 null을 반환하면
   * 현재 오류.
   *
   * @method Html5#오류
   * @return {MediaError|null}
   * 미디어 요소의 `error` 값입니다. 있는 경우 `MediaError`가 됩니다.
   *는 현재 오류이며 그렇지 않으면 null입니다.
   *
   * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error}
   */
  '오류',

  /**
   * 미디어 요소에서 `seeking` 값을 가져옵니다. '찾는다'는
   *미디어는 현재 새로운 직책을 구하고 있는지 아닌지.
   *
   * @method Html5#찾기
   * @return {부울}
   * - 미디어 요소에서 `찾는` 값입니다.
   * - True는 미디어가 현재 새로운 위치를 찾고 있음을 나타냅니다.
   * - False는 현재 미디어가 새로운 위치를 찾고 있지 않음을 나타냅니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking}
   */
  '찾다',

  /**
   * 미디어 요소에서 `seekable` 값을 가져옵니다. `검색 가능`은
   * 현재 '검색'할 수 있는 시간 범위를 나타내는 'TimeRange' 객체.
   *
   * @method Html5#검색 가능
   * @return {시간 범위}
   * 미디어 요소의 `seekable` 값입니다. `TimeRange` 객체
   * 탐색할 수 있는 현재 시간 범위를 나타냅니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable}
   */
  '찾을 수 있는',

  /**
   * 미디어 요소에서 `ended` 값을 가져옵니다. 'ended'는 다음 여부를 나타냅니다.
   * 미디어가 끝에 도달했는지 여부.
   *
   * @method Html5#ended
   * @return {부울}
   * - 미디어 요소의 `ended` 값입니다.
   * - True는 미디어가 종료되었음을 나타냅니다.
   * - False는 미디어가 종료되지 않았음을 나타냅니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}
   */
  '종료',

  /**
   * 미디어 요소에서 `playbackRate` 값을 가져옵니다. `playbackRate`는 다음을 나타냅니다.
   * 미디어가 현재 재생되는 속도. 예:
   * - playbackRate가 2로 설정되면 미디어가 두 배 빠르게 재생됩니다.
   * - playbackRate가 0.5로 설정되면 미디어가 절반만큼 빠르게 재생됩니다.
   *
   * @method Html5#playbackRate
   * @return {숫자}
   * 미디어 요소의 `playbackRate` 값입니다. 나타내는 숫자
   * 미디어의 현재 재생 속도, 여기서 1은 정상 속도입니다.
   *
   * @see [사양]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
   */
  '재생 속도',

  /**
   * 미디어 요소에서 `defaultPlaybackRate` 값을 가져옵니다. `defaultPlaybackRate`는 다음을 나타냅니다.
   * 미디어가 현재 재생되는 속도. 이 값은 현재를 나타내지 않습니다.
   * 재생이 시작된 후 `playbackRate`는 {@link Html5#playbackRate}를 사용합니다.
   *
   * 예:
   * - defaultPlaybackRate가 2로 설정되면 미디어가 두 배 빠르게 재생됩니다.
   * - defaultPlaybackRate가 0.5로 설정되면 미디어가 절반 속도로 재생됩니다.
   *
   * @method Html5.prototype.defaultPlaybackRate
   * @return {숫자}
   * 미디어 요소의 `defaultPlaybackRate` 값입니다. 나타내는 숫자
   * 미디어의 현재 재생 속도, 여기서 1은 정상 속도입니다.
   *
   * @see [사양]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
   */
  'defaultPlaybackRate',

  /**
   * video 요소에서 'disablePictureInPicture' 값을 가져옵니다.
   *
   * @method Html5#disablePictureInPicture
   * @return {부울} 값
   * - 동영상 요소의 'disablePictureInPicture' 값입니다.
   * - True는 비디오가 Picture-In-Picture 모드에서 재생될 수 없음을 나타냅니다.
   * - False는 비디오가 Picture-In-Picture 모드에서 재생될 수 있음을 나타냅니다.
   *
   * @see [사양]{@link https://w3c.github.io/picture-in-picture/#disable-pip}
   */
  '비활성화PictureInPicture',

  /**
   * 미디어 요소에서 `played` 값을 가져옵니다. `played`는 `TimeRange`를 반환합니다.
   * 재생된 미디어 타임라인의 지점을 나타내는 개체입니다.
   *
   * @method Html5#played
   * @return {시간 범위}
   * 미디어 요소의 `played` 값입니다. 나타내는 `TimeRange` 객체
   * 재생된 시간 범위.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played}
   */
  '놀았다',

  /**
   * 미디어 요소에서 `networkState` 값을 가져옵니다. `networkState`는 다음을 나타냅니다.
   * 현재 네트워크 상태. 다음 목록에서 열거형을 반환합니다.
   * - 0: NETWORK_EMPTY
   * - 1: 네트워크_유휴
   * - 2: 네트워크_로딩
   * - 삼: NETWORK_NO_SOURCE
   *
   * @method Html5#networkState
   * @return {숫자}
   * 미디어 요소의 `networkState` 값입니다. 이것은 숫자가 될 것입니다
   * 설명의 목록에서.
   *
   * @see [사양] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate}
   */
  '네트워크 상태',

  /**
   * 미디어 요소에서 `readyState` 값을 가져옵니다. 'readyState'는 다음을 나타냅니다.
   * 미디어 요소의 현재 상태. 에서 열거형을 반환합니다.
   * 다음 목록:
   * - 0: 아무것도 가지고 있지 않다
   * - 1: HAVE_METADATA
   * - 2: HAVE_CURRENT_DATA
   * - 삼: HAVE_FUTURE_DATA
   * - 4: HAVE_ENOUGH_DATA
   *
   * @method Html5#readyState
   * @return {숫자}
   * 미디어 요소의 `readyState` 값입니다. 이것은 숫자가 될 것입니다
   * 설명의 목록에서.
   *
   * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states}
   */
  '준비 상태',

  /**
   * video 요소에서 `videoWidth` 값을 가져옵니다. `videoWidth`는 나타냅니다.
   * 비디오의 현재 너비(css 픽셀 단위).
   *
   * @method Html5#videoWidth
   * @return {숫자}
   * 동영상 요소의 'videoWidth' 값입니다. 이것은 숫자가 될 것입니다
   * CSS 픽셀.
   *
   * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
   */
  '동영상 너비',

  /**
   * video 요소에서 `videoHeight` 값을 가져옵니다. `videoHeight`는 다음을 나타냅니다.
   * 비디오의 현재 높이(css 픽셀).
   *
   * @method Html5#videoHeight
   * @return {숫자}
   * 동영상 요소의 'videoHeight' 값입니다. 이것은 숫자가 될 것입니다
   * CSS 픽셀.
   *
   * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
   */
  '동영상 높이',

  /**
   * 미디어 요소에서 `crossOrigin` 값을 가져옵니다. 'crossOrigin'은 다음을 나타냅니다.
   * 요청과 함께 쿠키를 전송해야 하는 브라우저에
   * 다른 자산/재생 목록
   *
   * @method Html5#crossOrigin
   * @return {문자열}
   * - 익명은 미디어가 쿠키를 보내지 않아야 함을 나타냅니다.
   * - use-credentials는 미디어가 요청과 함께 쿠키를 전송해야 함을 나타냅니다.
   *
   * @see [사양]{@link https://html.spec.whatwg.org/#attr-media-crossorigin}
   */
  '크로스오리진'
].forEach(함수(소품) {
  Html5.prototype[prop] = 함수() {
    return this.el_[소품];
  };
});

// 다음 형식의 setter로 기본 속성을 래핑합니다.
// 설정 + toTitleCase(이름)
// 목록은 다음과 같습니다.
// setVolume, setSrc, setPoster, setPreload, setPlaybackRate, setDefaultPlaybackRate,
// setDisablePictureInPicture, setCrossOrigin
[
  /**
   * 미디어 요소에서 `볼륨` 값을 설정합니다. '볼륨'은 현재를 나타냅니다.
   * 소수점 형식의 백분율로 표시되는 오디오 레벨. 즉, 1은 100%, 0.5는 50%,
   * 곧.
   *
   * @method Html5#setVolume
   * @param {숫자} percentAsDecimal
   * 소수점으로 표시되는 부피 백분율입니다. 유효한 범위는 0-1입니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
   */
  '용량',

  /**
   * 미디어 요소에 `src` 값을 설정합니다. `src`는 현재
   * 미디어용 {@link Tech~SourceObject}.
   *
   * @method Html5#setSrc
   * @param {Tech~SourceObject} src
   * 현재 소스로 설정할 소스 개체입니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src}
   */
  '소스',

  /**
   * 미디어 요소에 `poster` 값을 설정합니다. 'poster'는 다음 URL입니다.
   * 사용 가능한 미디어 데이터가 없을 때 표시될 수 있는 이미지 파일.
   *
   * @method Html5#setPoster
   * @param {문자열} 포스터
   * 미디어의 '포스터'로 사용해야 하는 이미지의 URL
   * 요소.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster}
   */
  '포스터',

  /**
   * 미디어 요소에 `preload` 값을 설정합니다. '예압'은 다음을 나타냅니다.
   * 미디어가 상호 작용하기 전에 다운로드해야 하는 항목. 그것은 다음을 가질 수 있습니다
   * 값:
   * - 없음: 아무것도 다운로드하지 않아야 합니다.
   * - 메타데이터: 포스터와 미디어의 처음 몇 프레임을 다운로드하여 얻을 수 있습니다.
   * 미디어 크기 및 기타 메타데이터
   * - auto: 미디어 및 미디어에 대한 메타데이터가 이전에 다운로드되도록 허용
   * 상호 작용
   *
   * @method Html5#setPreload
   * @param {string} 사전 로드
   * 미디어 요소에 설정할 `preload` 값입니다. '없음', '메타데이터',
   * 또는 '자동'.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
   */
  '예압',

  /**
   * 미디어 요소에 `playbackRate` 값을 설정합니다. `playbackRate`는 다음을 나타냅니다.
   * 미디어가 재생되어야 하는 속도. 예:
   * - playbackRate가 2로 설정되면 미디어가 두 배 빠르게 재생됩니다.
   * - playbackRate가 0.5로 설정되면 미디어가 절반만큼 빠르게 재생됩니다.
   *
   * @method Html5#setPlaybackRate
   * @return {숫자}
   * 미디어 요소의 `playbackRate` 값입니다. 나타내는 숫자
   * 미디어의 현재 재생 속도, 여기서 1은 정상 속도입니다.
   *
   * @see [사양]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
   */
  '재생 속도',

  /**
   * 미디어 요소에 `defaultPlaybackRate` 값을 설정합니다. `defaultPlaybackRate`는 다음을 나타냅니다.
   * 초기 시작 시 미디어가 재생되어야 하는 속도. 이 값 변경
   * 비디오가 시작된 후에는 아무것도 하지 않습니다. 대신 {@link Html5#setPlaybackRate}를 사용해야 합니다.
   *
   * 예시 값:
   * - playbackRate가 2로 설정되면 미디어가 두 배 빠르게 재생됩니다.
   * - playbackRate가 0.5로 설정되면 미디어가 절반만큼 빠르게 재생됩니다.
   *
   * @method Html5.prototype.setDefaultPlaybackRate
   * @return {숫자}
   * 미디어 요소의 `defaultPlaybackRate` 값입니다. 나타내는 숫자
   * 미디어의 현재 재생 속도, 여기서 1은 정상 속도입니다.
   *
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultplaybackrate}
   */
  'defaultPlaybackRate',

  /**
   * 브라우저가 PIP(Picture-in-Picture) 상황에 맞는 메뉴를 제안하는 것을 방지합니다.
   * 또는 경우에 따라 Picture-in-Picture를 자동으로 요청합니다.
   *
   * @method Html5#setDisablePictureInPicture
   * @param {부울} 값
   * True 값은 Picture-in-Picture 모드를 비활성화합니다.
   *
   * @see [사양]{@link https://w3c.github.io/picture-in-picture/#disable-pip}
   */
  '비활성화PictureInPicture',

  /**
   * 미디어 요소에서 `crossOrigin` 값을 설정합니다. 'crossOrigin'은 다음을 나타냅니다.
   * 요청과 함께 쿠키를 전송해야 하는 브라우저에
   * 다른 자산/재생 목록
   *
   * @method Html5#setCrossOrigin
   * @param {문자열} crossOrigin
   * - 익명은 미디어가 쿠키를 보내지 않아야 함을 나타냅니다.
   * - use-credentials는 미디어가 요청과 함께 쿠키를 전송해야 함을 나타냅니다.
   *
   * @see [사양]{@link https://html.spec.whatwg.org/#attr-media-crossorigin}
   */
  '크로스오리진'
].forEach(함수(소품) {
  Html5.prototype['set' + toTitleCase(prop)] = function(v) {
    this.el_[prop] = v;
  };
});

// 네이티브 함수를 함수로 감싸기
// 목록은 다음과 같습니다.
// 일시 중지, 로드, 재생
[
  /**
   * 미디어 요소 `일시 중지` 기능을 감싸는 래퍼입니다. 그러면 `HTML5`가 호출됩니다.
   * 미디어 요소 `pause` 기능.
   *
   * @method Html5#pause
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause}
   */
  '정지시키다',

  /**
   * 미디어 요소 `로드` 기능을 감싸는 래퍼입니다. 그러면 `HTML5`가 호출됩니다.
   * 미디어 요소 `로드` 기능.
   *
   * @method Html5#로드
   * @see [사양]{@링크 https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load}
   */
  '짐',

  /**
   * 미디어 요소 `재생` 기능을 감싸는 래퍼입니다. 그러면 `HTML5`가 호출됩니다.
   * 미디어 요소 `재생` 기능.
   *
   * @method Html5#재생
   * @see [사양]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-play}
   */
  '놀다'
].forEach(함수(소품) {
  Html5.prototype[prop] = 함수() {
    return this.el_[prop]();
  };
});

Tech.withSourceHandlers(Html5);

/**
 * Html5용 기본 소스 핸들러는 단순히 소스를 미디어 요소에 전달합니다.
 *
 * @property {Tech~SourceObject} 소스
 * 소스 객체
 *
 * @property {Html5} 기술
 * HTML5 기술의 인스턴스입니다.
 */
Html5.nativeSourceHandler = {};

/**
 * 미디어 요소가 주어진 MIME 유형을 재생할 수 있는지 확인하십시오.
 *
 * @param {문자열} 유형
 * 확인할 mimetype
 *
 * @return {문자열}
 * 'probably', 'maybe' 또는 '' (빈 문자열)
 */
Html5.nativeSourceHandler.canPlayType = 함수(유형) {
  // MediaPlayer가 없는 IE는 오류를 발생시킵니다(#519).
  {
    return Html5.TEST_VID.canPlayType(유형);
  } 잡기 (e) {
    반품 '';
  }
};

/**
 * 미디어 요소가 기본적으로 소스를 처리할 수 있는지 확인하십시오.
 *
 * @param {Tech~SourceObject} 소스
 * 소스 객체
 *
 * @param {객체} [옵션]
 * 기술자에게 전달되는 옵션.
 *
 * @return {문자열}
 * 'probably', 'maybe' 또는 '' (빈 문자열).
 */
Html5.nativeSourceHandler.canHandleSource = 함수(소스, 옵션) {

  // 유형이 제공된 경우 해당 유형에 의존해야 합니다.
  if (소스.유형) {
    return Html5.nativeSourceHandler.canPlayType(source.type);

  // 유형이 없으면 'video/[EXTENSION]'을 확인합니다.
  } 그렇지 않으면 (source.src) {
    const ext = Url.getFileExtension(source.src);

    return Html5.nativeSourceHandler.canPlayType(`video/${ext}`);
  }

  반품 '';
};

/**
 * 소스를 네이티브 미디어 요소에 전달합니다.
 *
 * @param {Tech~SourceObject} 소스
 * 소스 객체
 *
 * @param {Html5} 기술
 * Html5 기술의 인스턴스
 *
 * @param {객체} [옵션]
 * 소스에 전달하는 옵션
 */
Html5.nativeSourceHandler.handleSource = function(source, tech, options) {
  tech.setSrc(source.src);
};

/**
 * 정리가 필요하지 않으므로 기본 처리 기능에 대한 noop입니다.
 */
Html5.nativeSourceHandler.dispose = function() {};

// 네이티브 소스 핸들러 등록
Html5.registerSourceHandler(Html5.nativeSourceHandler);

Tech.registerTech('Html5', Html5);
기본 HTML5 내보내기;