Reputation: 2891
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