How do i append two video files data to a source buffer using media source api?

后端 未结 4 530
闹比i
闹比i 2020-12-24 09:16

I have two videos name v11.webm and v12.webm.

What i want is that these two videos should run seamlessly without any gap.

I am following the media source a

相关标签:
4条回答
  • 2020-12-24 09:50

    Just set the sourceBuffer's mode to 'sequence' (default seems to be 'segments')

    From the doc: https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/mode

    sequence: The order in which the segments are appended to the SourceBuffer determines the order in which they are played. Segment timestamps are generated automatically for the segments that observe this order.

    In my app, I just set it after adding the the source buffer to the media source:

    // Create media source for the stream, and create the source buffer when ready
    let self = this;
    this._mediaSource = new MediaSource();
    this._mediaSource.addEventListener('sourceopen', function () {
      self._sourceBuffer = self.mediaSource.addSourceBuffer(environment.recordingMimeType);
      self._sourceBuffer.mode = 'sequence'; // This is the relevant part
      self._sourceBuffer.addEventListener('error', function (ev) {
        console.error("Source buffer error ??");
        console.error(ev);
      });
    });
    
    0 讨论(0)
  • 2020-12-24 09:54

    What I'm missing in your code is : mediaSource.endOfStream();

    Can you elaborate on the inconsistent mixing issue?

    0 讨论(0)
  • 2020-12-24 10:06

    I get perfect example to solve this problem into simple a way and short way...

    i am using three static files, but you can append data from socket's or any api also.

    <!DOCTYPE html>
    <html>
    
    <head>
    </head>
    
    <body>
      <br>
      <video controls="true" autoplay="true"></video>
    
      <script>
        (async() => {
    
    
          const mediaSource = new MediaSource();
    
          const video = document.querySelector("video");
    
          // video.oncanplay = e => video.play();
    
          const urls = ["https://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4", "https://raw.githubusercontent.com/w3c/web-platform-tests/master/media-source/mp4/test.mp4","https://nickdesaulniers.github.io/netfix/demo/frag_bunny.mp4"];
    
          const request = url => fetch(url).then(response => response.arrayBuffer());
    
          // `urls.reverse()` stops at `.currentTime` : `9`
          const files = await Promise.all(urls.map(request));
    
          /*
           `.webm` files
           Uncaught DOMException: Failed to execute 'appendBuffer' on 'SourceBuffer': This SourceBuffer has been removed from the parent media source.
           Uncaught DOMException: Failed to set the 'timestampOffset' property on 'SourceBuffer': This SourceBuffer has been removed from the parent media source.
          */
          // const mimeCodec = "video/webm; codecs=opus";
          // https://stackoverflow.com/questions/14108536/how-do-i-append-two-video-files-data-to-a-source-buffer-using-media-source-api/
          const mimeCodec = "video/mp4; codecs=avc1.42E01E, mp4a.40.2";
    
    
          const media = await Promise.all(files.map(file => {
            return new Promise(resolve => {
              let media = document.createElement("video");
              let blobURL = URL.createObjectURL(new Blob([file]));
              media.onloadedmetadata = async e => {
                resolve({
                  mediaDuration: media.duration,
                  mediaBuffer: file
                })
              }
              media.src = blobURL;
            })
          }));
    
          console.log(media);
    
          mediaSource.addEventListener("sourceopen", sourceOpen);
    
          video.src = URL.createObjectURL(mediaSource);
    
          async function sourceOpen(event) {
    
            if (MediaSource.isTypeSupported(mimeCodec)) {
              const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
    
              for (let chunk of media) {
                await new Promise(resolve => {
                  sourceBuffer.appendBuffer(chunk.mediaBuffer);
                  sourceBuffer.onupdateend = e => {
                    sourceBuffer.onupdateend = null;
                    sourceBuffer.timestampOffset += chunk.mediaDuration;
                    console.log(mediaSource.duration);
                    resolve()
                  }
                })
    
              }
    
              mediaSource.endOfStream();
    
            }  
            else {
              console.warn(mimeCodec + " not supported");
            }
          };
    
        })()
      </script>
    
    
    </body>
    
    </html>

    All credit goes to this person https://github.com/guest271314 who printed information.

    0 讨论(0)
  • 2020-12-24 10:10

    Perhaps a bit late, but I was able to figure this out. Your new video is overwriting the old one, because they both begin at time 0. You have to specify that your new video begins at time X before appending it, so your 'webkitsourceopen' event function should be:

    /* forget the sourcebuffer variable, we'll just manipulate mediaSource */
    mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');
    
    /* it seems ok to set initial duration 0 */
    var duration = 0;
    var totalVideos = 2;
    
    /* use this type of loop to ensure that that a single video
       is downloaded and appended before moving on to the next video,
       mediasource seems picky about these being in order */
    var i = 0;
    (function readChunk_(i){
    
        /* the GET function already returns a Uint8Array.
           the demo you linked reads it in filereader in order to manipulate it;
           you just want to immediately append it */
        GET('v1' + (i + 1) + '.webm', function(uint8Array){
    
            if(i == totalVideos) {
                mediaSource.endOfStream();
            } else {
    
                /* assuming your videos are put together correctly
                   (i.e. duration is correct), set the timestamp offset
                   to the length of the total video */
                mediaSource.sourceBuffers[0].timestampOffset = duration;
    
                mediaSource.sourceBuffers[0].append(uint8Array);
    
                /* set new total length */
                duration = mediaSource.duration;
    
                readChunk(++i);
            }
        });
    })(i);
    

    Now if only MediaSource wasn't so frustratingly picky about the structure of the videos it accepts. I have yet to find a single sample .webm that works besides the same one used in Eric Bidelman's Demo you linked.

    EDIT: After doing more testing, the way I set duration may not be correct. If you seem to get exponential duration growth after each append, try setting the timestampoffset to 0 and not changing it. I have no idea why that seems to fix it, and it may be a problem with how I'm generating the webm files.

    0 讨论(0)
提交回复
热议问题