Gary
Gary

Reputation: 2891

Trying to append audio/video content into source buffer of media source as file slices

the code below is an experiment to see if it is possible to read pieces of audio/video data from a database and feed it into a media source buffer. I started from this MDN example but changed it considerably to fit the scenario.

Ultimately, I want to read 1 MB pieces of data from a SQLite database (on the client) passed to a web extension through the native-messaging API; but, here, in this code sample, I'm selecting a video file using the file picker and slicing it into 1 MB pieces to feed into the media source following the MDN example.

The code breaks the file into 1024*1024 pieces until the final piece is smaller; and it all reaches the append_buffer() function and is appended to the source buffer; but the video never plays.

I'm likely doing something very stupid, but would you please tell me what I'm doing wrong?

What I am trying to do here is open a file, slice off 1 MB segments, use filereader to read the slice as a blob arrayBuffer and append that to the video media source buffer. I wanted it to begin to play before it all loaded, but the onplay event doesn't fire either; and it won't play after all the blobs are appended.

I know the video that I'm trying to load in this odd manner plays because it plays in the second video element where the video.src is set to its relative path.

<body>
  <video controls></video>
  <label><input type="file"></input>Hard Drive</label>
  <video controls src="untitled project.mp4"></video>
</body>

"use strict";
var video_file, mediaSource, sourceBuffer,
    chunk = 1024 * 1024,
    video = document.body.firstElementChild;

video.nextElementSibling.addEventListener( 'change', open_file, false );
video.addEventListener( 'canplay', () => { console.log( "Video can play." ); video.play(); }, true );

function open_file( evt )
 {
  video_file = evt.target.files[0]; 
  fetch_video.remaining = video_file.size;
  fetch_video.start = 0;
  mediaSource = new MediaSource();
  video.src = URL.createObjectURL( mediaSource );
  mediaSource.addEventListener( 'sourceopen', openSource );  
 } // close open_file

function openSource()
 {
   console.log( "Initialized." );
   sourceBuffer = mediaSource.addSourceBuffer( video_file.type ); 
   sourceBuffer.mode = "sequence";
   sourceBuffer.addEventListener('updateend', append_buffers );
   append_buffers();
 }

async function append_buffers()
 {
  var buf;
  if ( fetch_video.remaining > 0 )
    {
      buf = await fetch_video();
      if ( buf !== -1 )
        sourceBuffer.appendBuffer( buf );
      else 
        console.log( "error" );
    }
  else
    mediaSource.endOfStream();
}


function fetch_video()
 {
  return new Promise( ( resolve, reject ) =>
   {
    let f = fetch_video;
    f.end = f.start + Math.min( f.remaining, chunk );
    console.log( "start: " + f.start + ", end: " + f.end + ", remaining: " + f.remaining + ", end - start: " + ( f.end - f.start ) );
    if ( f.remaining > 0 )
        read_chunk( new Blob( [ video_file.slice( f.start, f.end ) ], { type : video_file.type } ) )
              .then( ( data ) => 
                    {
                      f.remaining = video_file.size - f.end;
                      f.start = f.end;
                      resolve( data );
                    },

                 ( err ) => { reject( -1 ); }
                 );
    else
      reject( - 1 );

  });
 } 

function read_chunk( blob )
  {          
    return new Promise( ( resolve, reject ) =>
      {
        let reader = new FileReader();
        reader.onload = () => { resolve( reader.result ); }; 
        reader.onerror = ( e ) => { reject(); }; 
        reader.readAsArrayBuffer( blob );
      }); // close new promise
  } 

Upvotes: 0

Views: 1834

Answers (0)

Related Questions