Redo av codec settings & selections to accomodate webm

Allows for ranked preferences for h264, av1, and vp9 codecs in
settings, along with equal preferences which are tiebroken using
smaller file size.

For each quality, gives av-merge a list of video sources
and audio sources sorted based on preference & file size. It
will pick the first one that the browser supports.

Closes #84

Signed-off-by: Jesús <heckyel@hyperbola.info>
This commit is contained in:
James Taylor
2021-09-06 12:58:27 -07:00
committed by Jesús
parent 854ab81b91
commit 9c7e93ecf8
7 changed files with 174 additions and 103 deletions

View File

@@ -19,13 +19,12 @@
// TODO: Call abort to cancel in-progress appends?
function AVMerge(video, srcPair, startTime){
this.videoSource = srcPair[0];
this.audioSource = srcPair[1];
if (this.videoSource.bitrate && this.audioSource.bitrate)
this.avRatio = this.audioSource.bitrate/this.videoSource.bitrate;
else
this.avRatio = 1/10;
function AVMerge(video, srcInfo, startTime){
this.audioSource = null;
this.videoSource = null;
this.avRatio = null;
this.videoStream = null;
this.audioStream = null;
this.seeking = false;
@@ -36,30 +35,48 @@ function AVMerge(video, srcPair, startTime){
this.opened = false;
this.audioEndOfStreamCalled = false;
this.videoEndOfStreamCalled = false;
this.setup();
}
AVMerge.prototype.setup = function() {
if (!('MediaSource' in window)) {
reportError('MediaSource not supported.');
return;
}
var audioSupported = MediaSource.isTypeSupported(
this.audioSource['mime_codec']
)
var videoSupported = MediaSource.isTypeSupported(
this.videoSource['mime_codec']
)
if (!audioSupported)
reportError('Unsupported MIME type or codec: ',
this.audioSource['mime_codec']);
if (!videoSupported)
reportError('Unsupported MIME type or codec: ',
this.videoSource['mime_codec']);
if (audioSupported && videoSupported) {
this.mediaSource = new MediaSource();
this.video.src = URL.createObjectURL(this.mediaSource);
this.mediaSource.onsourceopen = this.sourceOpen.bind(this);
// Find supported video and audio sources
for (var src of srcInfo['videos']) {
if (MediaSource.isTypeSupported(src['mime_codec'])) {
reportDebug('Using video source', src['mime_codec'],
src['quality_string'], 'itag', src['itag']);
this.videoSource = src;
break;
}
}
for (var src of srcInfo['audios']) {
if (MediaSource.isTypeSupported(src['mime_codec'])) {
reportDebug('Using audio source', src['mime_codec'],
src['quality_string'], 'itag', src['itag']);
this.audioSource = src;
break;
}
}
if (this.videoSource === null)
reportError('No supported video MIME type or codec found: ',
srcInfo['videos'].map(s => s.mime_codec).join(', '));
if (this.audioSource === null)
reportError('No supported audio MIME type or codec found: ',
srcInfo['audios'].map(s => s.mime_codec).join(', '));
if (this.videoSource === null || this.audioSource === null)
return;
if (this.videoSource.bitrate && this.audioSource.bitrate)
this.avRatio = this.audioSource.bitrate/this.videoSource.bitrate;
else
this.avRatio = 1/10;
this.setup();
}
AVMerge.prototype.setup = function() {
this.mediaSource = new MediaSource();
this.video.src = URL.createObjectURL(this.mediaSource);
this.mediaSource.onsourceopen = this.sourceOpen.bind(this);
}
AVMerge.prototype.sourceOpen = function(_) {

View File

@@ -20,10 +20,10 @@
qualityOptions.push(src.quality_string)
}
for (var src of data['pair_sources']) {
qualityOptions.push(src[0].quality_string)
qualityOptions.push(src.quality_string)
}
if (data['using_pair_sources'])
qualityDefault = data['pair_sources'][data['pair_idx']][0].quality_string;
qualityDefault = data['pair_sources'][data['pair_idx']].quality_string;
else if (data['uni_sources'].length != 0)
qualityDefault = data['uni_sources'][data['uni_idx']].quality_string;
else
@@ -108,7 +108,7 @@
}
} else {
for (var i=0; i < data['pair_sources'].length; i++) {
if (data['pair_sources'][i][0].quality_string == quality) {
if (data['pair_sources'][i].quality_string == quality) {
changeQuality({'type': 'pair', 'index': i});
return;
}

View File

@@ -4,16 +4,15 @@ function changeQuality(selection) {
var currentVideoTime = video.currentTime;
var videoPaused = video.paused;
var videoSpeed = video.playbackRate;
var videoSource;
var srcInfo;
if (avMerge)
avMerge.close();
if (selection.type == 'uni'){
videoSource = data['uni_sources'][selection.index];
video.src = videoSource.url;
srcInfo = data['uni_sources'][selection.index];
video.src = srcInfo.url;
} else {
let srcPair = data['pair_sources'][selection.index];
videoSource = srcPair[0];
avMerge = new AVMerge(video, srcPair, currentVideoTime);
srcInfo = data['pair_sources'][selection.index];
avMerge = new AVMerge(video, srcInfo, currentVideoTime);
}
video.currentTime = currentVideoTime;
if (!videoPaused){
@@ -26,7 +25,6 @@ function changeQuality(selection) {
var avMerge;
if (data.using_pair_sources) {
var srcPair = data['pair_sources'][data['pair_idx']];
var videoSource = srcPair[0];
// Do it dynamically rather than as the default in jinja
// in case javascript is disabled
avMerge = new AVMerge(video, srcPair, 0);