github.com/0chain/gosdk@v1.17.11/wasmsdk/demo/player.js (about)

     1  async function stopPlay({goWasm, videoElement}){
     2  
     3    if (!videoElement) {
     4      throw new Error('video element is required');
     5    }
     6  
     7    await goWasm.sdk.stop()
     8  
     9    videoElement.pause()
    10    URL.revokeObjectURL(videoElement.src);
    11  }
    12  
    13  async function startPlay({
    14    goWasm,
    15    allocationId,
    16    containerElement,
    17    videoElement,
    18    remotePath,
    19    authTicket = '',
    20    lookupHash = '',
    21    mimeType = '',
    22    isLive = false,
    23  }) {
    24    if (!videoElement) {
    25      throw new Error('video element is required');
    26    }
    27  
    28  	videoElement.addEventListener('error', function () {
    29      	switch (videoElement.error.code) {
    30          	case videoElement.error.MEDIA_ERR_ABORTED:
    31              	console.error("Fetch aborted by the user.");
    32              	break;
    33          	case videoElement.error.MEDIA_ERR_NETWORK:
    34              	console.error("Network error occurred.");
    35              	break;
    36          	case videoElement.error.MEDIA_ERR_DECODE:
    37              	console.error("Media decoding failed.");
    38              	break;
    39          	case videoElement.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
    40              	console.error("Media not supported.");
    41              	break;
    42          	default:
    43              	console.error("An unknown error occurred.");
    44              	break;
    45      	}
    46  	});
    47  
    48  
    49    await goWasm.sdk.play(
    50        allocationId, remotePath, authTicket, lookupHash, isLive);
    51  
    52    if (isLive) {
    53      return playStream({goWasm, videoElement,allocationId,remotePath,authTicket, lookupHash});
    54    }
    55  
    56    // first segment
    57    const buf = await goWasm.sdk.getNextSegment();
    58  
    59    const {isFragmented, mimeCodecs} = getMimeCodecs({mimeType, buf});
    60  
    61    // const mimeCodecs = `${mimeType};
    62    // codecs="${muxjs.mp4.probe.tracks(buf).map(t => t.codec).join(",")}"`;
    63    console.log(
    64        `playlist: isFragmented:${isFragmented} mimeCodecs:${mimeCodecs}`);
    65  
    66    if (isFragmented && MediaSource.isTypeSupported(mimeCodecs)) {
    67      return playChunks({goWasm, videoElement, buf, mimeCodecs});
    68    }
    69  
    70    goWasm.sdk.stop();
    71    // allocationID, remotePath, authTicket, lookupHash string,
    72    // downloadThumbnailOnly, autoCommit bool
    73    const {url} = await goWasm.sdk.download(
    74        allocationId, remotePath, authTicket, lookupHash, false,10,"");
    75        videoElement.crossOrigin = 'anonymous';
    76        videoElement.src = url
    77  
    78    var promise = videoElement.play();
    79    if (promise !== undefined) {
    80        promise.catch(err => {
    81          // Auto-play was prevented
    82          while (videoElement.lastElementChild) {
    83            videoElement.removeChild(videoElement.lastElementChild);
    84          }
    85          videoElement.removeAttribute("src")
    86  
    87          const source = document.createElement("source")
    88          source.setAttribute("src", url)
    89          source.setAttribute("type", mimeType)
    90          videoElement.appendChild(source)
    91  
    92          videoElement.setAttribute("muted",true)
    93          videoElement.setAttribute("autoplay",true)
    94          videoElement.setAttribute("playsinline",true)
    95          videoElement.setAttribute("loop",true)
    96          setTimeout(function() {
    97                // weird fix for safari
    98                containerElement.innerHTML = videoElement.outerHTML;
    99          }, 100);
   100        }).then(() => {
   101            // Auto-play started
   102        });
   103    }
   104  }
   105  
   106  
   107  async function playStream({
   108    goWasm,
   109    videoElement,
   110    allocationId,
   111    remotePath,
   112    authTicket,
   113    lookupHash
   114  }) {
   115    await goWasm.sdk.play(
   116        allocationId, remotePath, authTicket, lookupHash, true);
   117  
   118    const mimeCodecs = 'video/mp4; codecs="mp4a.40.2,avc1.64001f"';
   119  
   120    if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodecs)) {
   121      let sourceBuffer;
   122  
   123      const transmuxer = new muxjs.mp4.Transmuxer();
   124      const mediaSource = new MediaSource();
   125  
   126      const getNextSegment = async () => {
   127        try {
   128          const buf = await goWasm.sdk.getNextSegment()
   129  
   130          if (buf?.length > 0) {
   131            transmuxer.push(new Uint8Array(buf))
   132            transmuxer.flush()
   133          }
   134        } catch (err) {
   135          getNextSegment()
   136        }
   137      };
   138  
   139      transmuxer.on('data', segment => {
   140        const data = new Uint8Array(
   141            segment.initSegment.byteLength + segment.data.byteLength);
   142        data.set(segment.initSegment, 0);
   143        data.set(segment.data, segment.initSegment.byteLength);
   144        // To inspect data use =>
   145        // console.log(muxjs.mp4.tools.inspect(data));
   146        sourceBuffer.appendBuffer(data);
   147      })
   148  
   149      mediaSource.addEventListener('sourceopen', async () => {
   150        sourceBuffer = mediaSource.addSourceBuffer(mimeCodecs);
   151        sourceBuffer.mode = 'sequence';
   152        sourceBuffer.addEventListener('updateend', getNextSegment);
   153  
   154        await getNextSegment();
   155  
   156        videoElement.play();
   157  
   158        URL.revokeObjectURL(videoElement.src);
   159      })
   160  
   161      videoElement.src = URL.createObjectURL(mediaSource);
   162      videoElement.crossOrigin = 'anonymous';
   163    } else {
   164      throw new Error('Unsupported MIME type or codec: ', mimeCodecs);
   165    }
   166  }
   167  
   168  
   169  async function playChunks({goWasm, videoElement, buf, mimeCodecs}) {
   170    let sourceBuffer;
   171  
   172    const mediaSource = new MediaSource();
   173  
   174    videoElement.src = URL.createObjectURL(mediaSource);
   175    videoElement.crossOrigin = 'anonymous';
   176  
   177    const getNextSegment = async () => {
   178      try {
   179        const buffer = await goWasm.sdk.getNextSegment()
   180  
   181        if (buffer?.length > 0) {
   182          sourceBuffer.appendBuffer(new Uint8Array(buffer))
   183        }
   184        else {
   185          if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
   186            mediaSource.endOfStream()
   187          }
   188        }
   189      } catch (err) {
   190        getNextSegment()
   191      }
   192    };
   193  
   194    mediaSource.addEventListener('sourceopen', async () => {
   195      sourceBuffer = mediaSource.addSourceBuffer(mimeCodecs);
   196      sourceBuffer.mode = 'sequence'
   197      sourceBuffer.addEventListener('updateend', getNextSegment)
   198      sourceBuffer.appendBuffer(buf)
   199      videoElement.play()
   200    })
   201  }
   202  
   203  
   204  function detectMp4({mimeType, buf}) {
   205    const isFragmented =
   206        muxjs.mp4.probe.findBox(buf, ['moov', 'mvex']).length > 0 ? true : false;
   207  
   208    return {
   209      isFragmented,
   210          mimeCodecs: `${mimeType}; codecs="${
   211              muxjs.mp4.probe.tracks(buf).map(t => t.codec).join(',')}"`,
   212    }
   213  }
   214  
   215  function detectWebm({mimeType, buf}) {
   216    const decoder = new EBML.Decoder();
   217    const codecs =
   218        decoder.decode(buf)
   219            .filter(it => it.name == 'CodecID')
   220            .map(it => it.value.replace(/^(V_)|(A_)/, '').toLowerCase())
   221            .join(',')
   222    return {
   223      isFragmented: true, mimeCodecs: `${mimeType}; codecs="${codecs}"`
   224    }
   225  }
   226  
   227  const detectors = {
   228    'video/mp4': detectMp4,
   229    'audio/mp4': detectMp4,
   230    'video/webm': detectWebm,
   231    'audio/webm': detectWebm,
   232  }
   233  
   234  function getMimeCodecs({mimeType, buf}) {
   235    const detect = detectors[mimeType];
   236    if (detect) {
   237      return detect({mimeType, buf})
   238    }
   239    return mimeType
   240  }