123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- function VideoMediaSource(element) {
- let videoElement = null;
- let codecInfo = null;
- let mediaSource = null;
- let sourceBuffer = null;
- let initSegmentData = null;
- let ctrlDelayFlag = false;
- let delay = 4;
- const DELAY = 0.5;
- let waitingCount = 0;
- let time = 0;
- let segmentWaitDecode = [];
- let firstTimeStamp = null;
- let isFirstTimeStamp = false;
- let onDurationChangeCallback = null;
- let onCanplayCallback = null;
- let startPlay = false;
- function constructor(element) {
- videoElement = element;
- }
- constructor.prototype = {
- init() {
- videoElement.controls = false;
- videoElement.autoplay = 'autoplay';
- //videoElement.preload = "auto";
- videoElement.muted = true;
- addVideoEventListener(videoElement);
- appendInitSegment();
- },
- setMediaSegment(mediaSegment) {
- appendNextMediaSegment(mediaSegment)
- },
- setFirstTimeStamp(time) {
- if(!isFirstTimeStamp) {
- console.log('set firstTimeStamp:', time)
- firstTimeStamp = time;
- isFirstTimeStamp = true;
- }
- },
- setDurationChangeCallBack(callback) {
- onDurationChangeCallback = callback;
- },
- set CodecInfo(CodecInfo) {
- codecInfo = CodecInfo;
- },
- get CodecInfo() {
- return codecInfo;
- },
- set InitSegment(data) {
- initSegmentData = data;
- },
- get InitSegment() {
- return initSegmentData;
- },
- onCanplayCallback(callback) {
- onCanplayCallback = callback;
- },
- close() {
- videoElement.pause();
- removeEventListener();
- mediaSource.removeSourceBuffer(sourceBuffer);
- mediaSource.endOfStream();
- sourceBuffer = null;
- mediaSource = null;
- videoElement = null;
- }
- }
- return new constructor(element);
- function appendInitSegment() {
- if(mediaSource == null || mediaSource.readyState === 'end') {
- mediaSource = new MediaSource();
- addMediaSourceEventListener(mediaSource);
- videoElement.src = window.URL.createObjectURL(mediaSource);
- //console.log('new MediaSource');
- return;
- }
- //console.log('appendInitSegment start');
- if(mediaSource.sourceBuffers.length === 0) {
- mediaSource.duration = 0;
- let codecs = 'video/mp4;codecs="avc1.' + codecInfo + '"';
- if(!MediaSource.isTypeSupported(codecs)) {
- //console.log('要播放视频格式 video/mp4;codecs="avc1.64002a", video/mp4;codecs="avc1.64002a",您还需要安装一个额外的微软组件,参见 https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows')
- console.log('not support ' + codecs)
- return;
- }
- sourceBuffer = mediaSource.addSourceBuffer(codecs);
- addSourceBufferEventListener(sourceBuffer);
- }
- let initSegment = initSegmentData;
- if(initSegment == null) {
- mediaSource.endOfStream();
- console.log('no initSegmentData');
- }
- //console.log(sourceBuffer)
- sourceBuffer.appendBuffer(initSegment);
- //console.log(sourceBuffer)
- // saveAs(new File(initSegment, "test"));
- // Savesegments.set(initSegment, 0);
- // segmentsLength += initSegment.length;
- // segmentsNum --;
- console.log('appendInitSegment end')
- checkDelay();
- }
- function appendNextMediaSegment(mediaData) {
- if(sourceBuffer == null) {
- segmentWaitDecode.push(mediaData);
- return;
- }
- //console.log(mediaSource.readyState, mediaSource.readyState,sourceBuffer.updating)
- if(mediaSource.readyState === 'closed' || mediaSource.readyState === "ended") {
- console.log('mediaSource closed or ended')
- return;
- }
- if(onDurationChangeCallback) {
- //90000为采样率,先写死
- let rtpTimestamp = parseInt((videoElement.currentTime.toFixed(2) * 90000).toFixed(0)) + firstTimeStamp + 3600;//
- //console.log('callback time: ', rtpTimestamp)
- //console.log('sourceBuffer: ', sourceBuffer.timestampOffset)
- onDurationChangeCallback(rtpTimestamp);
- }
- //console.count('一帧');
- //try {
- if(segmentWaitDecode.length) {
- segmentWaitDecode.push(mediaData);
- //console.log(segmentWaitDecode)
- }else {
- if(!sourceBuffer.updating) {
- sourceBuffer.appendBuffer(mediaData);
- } else {
- segmentWaitDecode.push(mediaData);
- }
- }
- //}catch (e){
- // console.log('appendNextMediaSegment Error')
- //}
- if(sourceBuffer && sourceBuffer.buffered && sourceBuffer.buffered.length && sourceBuffer.buffered.end(0) > DELAY) {
- if(!startPlay) {
- videoElement.play();
- console.warn('playbakrate: ', videoElement.playbackRate)
- ctrlDelayFlag = true;
- }
- startPlay = true;
- } else {
- if(!startPlay) {
- videoElement.pause();
- }
- }
- //console.log(sourceBuffer)
- }
- /**
- * Video事件
- * @param videoElement video对象
- */
- function addVideoEventListener(videoElement) {
- videoElement.addEventListener('loadstart', onloadstart);
- videoElement.addEventListener('waiting', onWaiting);
- videoElement.addEventListener('durationchange', onDurationChange);
- videoElement.addEventListener('timeupdate', timeupdate);
- videoElement.addEventListener('canplay', oncanplay);
- videoElement.addEventListener('canplaythrough', oncanplaythrough);
- videoElement.addEventListener('error', onVideoError);
- document.addEventListener('visibilitychange', onVisibilityChange);
- }
- function onVisibilityChange(e) {
- if(document.visibilityState === 'visible') {
- ctrlDelayFlag = true;
- checkDelay();
- videoElement.play();
- } else {
- ctrlDelayFlag = false;
- videoElement.pause();
- }
- console.warn('visibilityState: ', document.visibilityState)
- }
- function onloadstart() {
- console.log('loadstart');
- }
- function onDurationChange() {
- //console.log('durationchange');
- if (mediaSource === null) {
- return;
- }
- if(sourceBuffer && sourceBuffer.buffered && sourceBuffer.buffered.length > 0) {
- checkBuffer();
- }
- //console.log('currentTime:', videoElement.currentTime);
- // if(onDurationChangeCallback) {
- // //90000为采样率,先写死
- // let rtpTimestamp = videoElement.currentTime * 90000 + firstTimeStamp ;
- // //console.log('callback time: ', rtpTimestamp)
- // onDurationChangeCallback(rtpTimestamp);
- // }
- //try {
- //}catch(e) {
- // console.log('sourceBuffer has been moved')
- //}
- }
- function checkDelay() {
- if(sourceBuffer && sourceBuffer.buffered && sourceBuffer.buffered.length > 0) {
- if(ctrlDelayFlag) {
- let startTime = sourceBuffer.buffered.start(0);
- let endTime = sourceBuffer.buffered.end(0);
- let diffTime = (videoElement.currentTime === 0 ? endTime - startTime: endTime - videoElement.currentTime).toFixed(2);
- if(diffTime >= delay + 0.5) {
- if(sourceBuffer.updating) {
- return;
- }
- let tempCurrntTime = endTime - delay;
- console.log('跳秒前', videoElement.currentTime)
- videoElement.currentTime = tempCurrntTime.toFixed(3);
- console.log('跳秒后', videoElement.currentTime, sourceBuffer.buffered.end(0), videoElement.duration)
- //ctrlDelayFlag = false;
- } else if((diffTime < DELAY + 0.2 ) && diffTime >= DELAY) {
- //console.warn('playbackRate:', 1, diffTime)
- videoElement.playbackRate = 1;
- }
- else if(diffTime < DELAY) {
- //console.warn('playbackRate:', 0.9, diffTime)
- videoElement.playbackRate = 0.9;
- }else {
- //console.warn('playbackRate:', 1.1, diffTime)
- videoElement.playbackRate = 1.1;
- }
- }
- }
- window.requestAnimationFrame(checkDelay);
- }
- function timeupdate() {
- // console.log('******timeupdate******');
- // console.log(videoElement.currentTime);
- // console.log('******timeupdate end******')
- }
- function oncanplay() {
- // if(isFirstTimeStamp && (firstTimeStamp == null)) {
- // //firstTimeStamp =
- // isFirstTimeStamp = false;
- // }
- onCanplayCallback && onCanplayCallback(videoElement);
- console.log('canplay');
- }
- function oncanplaythrough() {
- if(document.visibilityState === 'visible' && startPlay){ctrlDelayFlag = true};
- // console.log('canplaythrough');
- }
- function onVideoError() {
- console.error('error');
- //console.log(e)
- console.error(videoElement.currentTime);
- console.error("Error " + videoElement.error.code + "; details: " + videoElement.error.message);
- }
- /**
- * MediaSource事件
- * @param mediaSource
- */
- function addMediaSourceEventListener(mediaSource) {
- mediaSource.addEventListener('sourceopen', onSourceOpen);
- mediaSource.addEventListener('error', onMediaSourceError);
- }
- function onSourceOpen() {
- console.log('OnsourceOpen');
- appendInitSegment(); //此处重新调用一次,是为了建立sourceBuffer
- }
- function onMediaSourceError() {
- console.log('mediaSource error');
- console.log(videoElement.currentTime)
- }
- /**
- * sourceBuffer事件
- */
- function addSourceBufferEventListener(sourceBuffer) {
- sourceBuffer.addEventListener('error', onSourceBufferError);
- sourceBuffer.addEventListener('update', onUpdate);
- }
- function onSourceBufferError() {
- console.log('sourceBuffer Error');
- console.log(videoElement.currentTime)
- }
- function onUpdate() {
- //console.log('sourceBuffer update');
- if(segmentWaitDecode.length > 0) {
- if(!sourceBuffer.updating) {
- sourceBuffer.appendBuffer(segmentWaitDecode[0]);
- //console.log('segmentWaitDecode: ' + segmentWaitDecode.length)
- segmentWaitDecode.shift();
- }
- }
- //console.log(e)
- }
- function checkBuffer() {
- let minute = 60;
- let bufferTime = 30;
- let startTime = sourceBuffer.buffered.start(0);
- let endTime = sourceBuffer.buffered.end(0);
- //console.log(endTime- videoElement.currentTime)
- if (!sourceBuffer.updating && (endTime - startTime > minute)) {
- sourceBuffer.remove(startTime, endTime - bufferTime);
- videoElement.play();
- console.log('remove buffer: ', startTime, ' - ', (endTime - bufferTime))
- }else if(sourceBuffer.updating && (endTime - startTime > minute)) {
- console.log('clear buffer failed!')
- }
- }
- function onWaiting() {
- // console.log('waiting....');
- ctrlDelayFlag = false;
- // if(delay < 0.7) {
- // if(waitingCount === 0) {
- // time = Date.now();
- // waitingCount++;
- // }else {
- // if((Date.now() - time) <= 5000) {
- // waitingCount ++;
- // if(waitingCount >= 5) {
- // delay += 0.1;
- // console.log('delay: ', delay);
- // time = Date.now();
- // waitingCount = 0;
- // }
- // } else {
- // waitingCount = 1;
- // time = Date.now();
- // }
- // }
- // }
- }
- function removeEventListener() {
- document.removeEventListener('visibilitychange', onVisibilityChange);
- videoElement.removeEventListener('loadstart', onloadstart);
- videoElement.removeEventListener('waiting', onWaiting);
- videoElement.removeEventListener('durationchange', onDurationChange);
- videoElement.removeEventListener('timeupdate', timeupdate);
- videoElement.removeEventListener('canplay', oncanplay);
- videoElement.removeEventListener('canplaythrough', oncanplaythrough);
- videoElement.removeEventListener('error', onVideoError);
- mediaSource.removeEventListener('sourceopen', onSourceOpen);
- mediaSource.removeEventListener('error', onMediaSourceError);
- sourceBuffer.removeEventListener('error', onSourceBufferError);
- sourceBuffer.removeEventListener('update', onUpdate);
- }
- }
- export default VideoMediaSource;
|