From e201f93f71833e065e6cf6394e1693aa799dba10 Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 13:51:32 +0100 Subject: [PATCH 01/13] Add WISH ABR demo --- player/custom-wish-abr/README.md | 10 + player/custom-wish-abr/css/style.css | 18 + player/custom-wish-abr/demo.js | 34 ++ player/custom-wish-abr/icon.svg | 1 + player/custom-wish-abr/index.html | 50 +++ player/custom-wish-abr/info.json | 27 ++ player/custom-wish-abr/js/script.js | 512 +++++++++++++++++++++++++++ 7 files changed, 652 insertions(+) create mode 100644 player/custom-wish-abr/README.md create mode 100644 player/custom-wish-abr/css/style.css create mode 100644 player/custom-wish-abr/demo.js create mode 100755 player/custom-wish-abr/icon.svg create mode 100644 player/custom-wish-abr/index.html create mode 100644 player/custom-wish-abr/info.json create mode 100644 player/custom-wish-abr/js/script.js diff --git a/player/custom-wish-abr/README.md b/player/custom-wish-abr/README.md new file mode 100644 index 00000000..60a932e3 --- /dev/null +++ b/player/custom-wish-abr/README.md @@ -0,0 +1,10 @@ +# Custom WISH ARB + +Showcasing the player's ability to implement custom ABR using adaptation callback API. + +### Tags + +- adaptation logic +- adaption +- bitrate +- quality-switching diff --git a/player/custom-wish-abr/css/style.css b/player/custom-wish-abr/css/style.css new file mode 100644 index 00000000..373ef8e1 --- /dev/null +++ b/player/custom-wish-abr/css/style.css @@ -0,0 +1,18 @@ +body .demo-detail .code-example { + margin-top: 0; +} + +@media (min-width: 1200px) { + .player-col { + float: left; + } + + .code-col { + float: right; + } +} + +body:not(.fullscreen) :not(.no-frame).phone-frame::before { + top: 0; + left: 0; +} \ No newline at end of file diff --git a/player/custom-wish-abr/demo.js b/player/custom-wish-abr/demo.js new file mode 100644 index 00000000..86b15ca1 --- /dev/null +++ b/player/custom-wish-abr/demo.js @@ -0,0 +1,34 @@ +var availableRepresentations = []; + +function onVideoAdaptationHandler(param) { + var suggestedRep = availableRepresentations.filter((rep) => rep.id === param.suggested)[0]; + if (suggestedRep) { + console.log('Suggested representation: ' + availableRepresentations[i].bitrate / 1000 + 'kbps'); + } +} + +var conf = { + key: '', + adaptation: { + desktop: { + onVideoAdaptation: onVideoAdaptationHandler, + }, + mobile: { + onVideoAdaptation: onVideoAdaptationHandler, + }, + }, +}; + +var source = { + dash: 'https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/mpds/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.mpd', + hls: 'https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8', + progressive: 'https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/MI201109210084_mpeg-4_hd_high_1080p25_10mbits.mp4', + poster: 'https://cdn.bitmovin.com/content/assets/art-of-motion-dash-hls-progressive/poster.jpg', +}; + +var playerContainer = document.getElementById('player-container'); +var player = new bitmovin.player.Player(playerContainer, conf); + +player.load(source).then(function () { + availableRepresentations = player.getAvailableVideoQualities(); +}); diff --git a/player/custom-wish-abr/icon.svg b/player/custom-wish-abr/icon.svg new file mode 100755 index 00000000..c0294f73 --- /dev/null +++ b/player/custom-wish-abr/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/player/custom-wish-abr/index.html b/player/custom-wish-abr/index.html new file mode 100644 index 00000000..12303cda --- /dev/null +++ b/player/custom-wish-abr/index.html @@ -0,0 +1,50 @@ + + + + + +
+

+ The adaptive bitrate choosing feature of the Bitmovin Player can avoid re-buffering and minimize the + startup time, while targeting selected mode. +

+

+ Select desired ABR mode and start the video below to see the ABR feature in action. +

+
+ +
+
+
+
+ + +

+ + +

+ +
+
+
+
+
+
+

Bitrate

+
+
+
+
+
+ ${code:demo.js} +
+
diff --git a/player/custom-wish-abr/info.json b/player/custom-wish-abr/info.json new file mode 100644 index 00000000..53db1dd2 --- /dev/null +++ b/player/custom-wish-abr/info.json @@ -0,0 +1,27 @@ +{ + "title": "WISH ABR Algorithm", + "description": "Showcasing the player's ability to implement custom WISH ABR algorithm as own adaptation logic", + "long_descripition": "The adaptation logic in the player is the key to avoiding buffering and minimizing startup time. Custom adaptation gives you complete control over your player.", + "executable": { + "executable": true, + "indexfile": "index.html" + }, + "code": { + "show_code": true, + "language": "js", + "files": [ + "demo.js" + ] + }, + "metadata":{ + "title":"Adaptive Bitrate Supported Player » Demo | Bitmovin", + "description": "Support your AVOD service with Bitmovin's ad insertion supported video player during any video position | VAST, VPAID, IMA & VMAP Supported ✅" + }, + "tags": [ + "adaptation logic", + "adaption", + "bitrate", + "quality-switching" + ], + "priority": 800 +} \ No newline at end of file diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js new file mode 100644 index 00000000..ee291653 --- /dev/null +++ b/player/custom-wish-abr/js/script.js @@ -0,0 +1,512 @@ +(function () { + var qualitySwitches = 0; + var buffer_size = 20; + var throughputHistory = []; + var currentQuality = null; + var sameRepCount = 0; + var MIN_BUFFER_RATIO = 0.2; + var alpha = 0; + var beta = 0; + var gamma = 0; + var denominator_exp = 0; + var smoothThroughputKbps = 0; + var num_downloaded_segments = 0; + var selected_quality_index_array = []; + var availableVideoQualities; + var last_selected_quality = 0; + var next_selected_quality = 0; + var bitratesKbps; + var SD = 4; + var currentBufferS; + var lastBufferS; + var downloadedData; + var low_buff_thresS = 0; + var lastThroughputKbps = 0; + var qualityFunction = null; + var multiplier = 1; + var m_xi = 0; + var m_delta = 0; + var maxBufferLevel = null; + var videoThroughputKbps = 0; + var audioThroughputKbps = 0; + var qualityLevelList = []; + + var data; + var chart; + var dataset = [ + [ + "segmentNumber", + "Estimated throughput (Mbps)", + "Chosen quality (Mbps)", + "Buffer Length (x10s)", + ], + [0, 0, 0, 0], + ]; + + var playerConfig = { + key: "29ba4a30-8b5e-4336-a7dd-c94ff3b25f30", + analytics: { + key: "45adcf9b-8f7c-4e28-91c5-50ba3d442cd4", + videoId: "custom-adaptation", + }, + playback: { + muted: true, + autoplay: true, + }, + style: { + width: "640px", + height: "480px", + }, + tweaks: { + file_protocol: true, + app_id: "ANY_ID", + max_buffer_level: buffer_size, + }, + adaptation: { + onVideoAdaptation: wishmmsp, + }, + }; + + var container = document.getElementById("my-player"); + var applyButton = document.getElementById("applyWishConfig"); + var player = new bitmovin.player.Player(container, playerConfig); + + var sourceConfig = { + dash: "https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd", + }; + + function getUserConfiguration() { + var preference = document.getElementById("preferences"); + + switch (preference.value) { + case "save_data": + m_xi = 1; + m_delta = 1; + break; + case "balance": + m_xi = 0.75; + m_delta = 0.75; + break; + case "high_quality": + m_xi = 0.5; + m_delta = 0.5; + break; + } + + player + .load(sourceConfig) + .then(function () { + console.log("Successfully loaded Source Config!"); + }) + .catch(function (reason) { + console.log("Error while loading source:", reason); + }); + } + + applyButton.addEventListener("click", getUserConfiguration); + availableVideoQualities = player.getAvailableVideoQualities(); + currentBufferS = player.getVideoBufferLength(); + + function wishmmsp() { + next_selected_quality = 0; + bitratesKbps = availableVideoQualities.map(function (quality) { + return quality.bitrate / 1000; + }); + + // sort bitrates + bitratesKbps.sort(function (a, b) { + if (a === Infinity) return 1; + else if (isNaN(a)) return -1; + else return a - b; + }); + + currentBufferS = player.getVideoBufferLength(); + + if (!player) { + return; + } + + if ( + player.getConfig().hasOwnProperty("tweaks") && + player.getConfig().tweaks.hasOwnProperty("max_buffer_level") + ) { + maxBufferLevel = player.getConfig().tweaks.max_buffer_level; + } else { + maxBufferLevel = 20; + } + + var init = function () { + player.on( + bitmovin.player.PlayerEvent.DownloadFinished, + onDownloadFinished + ); + player.on(bitmovin.player.PlayerEvent.SegmentPlayback, function (data) { + SD = data.duration; + }); + }; + + if (player.getSource()) { + init(); + } else { + player.on(bitmovin.player.PlayerEvent.SourceLoaded, init); + } + + var nextQuality = onVideoAdaptation(); + return nextQuality.id; + } + + function resetBuffer() { + console.log(" resetBuffer "); + throughputHistory = []; + } + + // Graph drawing + if (getBrowser() === BROWSER.SAFARI) { + document.getElementById("chart-wrapper").style.display = "none"; + } + + google.charts.load("current", { packages: ["corechart"] }); + + google.charts.setOnLoadCallback(function () { + chart = new google.visualization.LineChart( + document.getElementById("curve_chart") + ); + drawLineChart(); + }); + + function newValue(metrics) { + var throughput; + if (metrics.throughput > 5000) { + throughput = 5000; + } else { + throughput = metrics.throughput; + } + + var chosenQuality = player.getDownloadedVideoData().bitrate; + + console.log( + "troughput: " + throughput + "\n picked quality: " + chosenQuality + ); + + segmentNumber += 1; + + dataset.push([ + segmentNumber, + throughput / 1000, + parseInt(chosenQuality) / 1000000, + player.getVideoBufferLength() / 10, + ]); + + drawLineChart(); + } + + function onDownloadFinished(event) { + var instantThroughputKbps = + event.size > 2000 + ? (event.size * 8) / 1000 / event.downloadTime + : lastThroughputKbps; + if (event.downloadType === "media/video") { + videoThroughputKbps = instantThroughputKbps; + lastThroughputKbps = Math.max(videoThroughputKbps, audioThroughputKbps); + } else { + audioThroughputKbps = instantThroughputKbps; + lastThroughputKbps = Math.max(videoThroughputKbps, audioThroughputKbps); + } + + // Data for graph rendering + if ( + data.downloadType.indexOf("media") !== -1 && + data.mimeType.indexOf("video") !== -1 && + data.size > 1000 + ) { + newValue({ + throughput: Math.round((data.size * 8) / data.downloadTime / 1000), + }); + } + } + + function getSmoothThroughput( + margin, + lastThroughputKbps, + smoothThroughputKbps + ) { + if (lastThroughputKbps > 0) { + if (smoothThroughputKbps === 0) { + smoothThroughputKbps = lastThroughputKbps; + } else { + smoothThroughputKbps = + (1 - margin) * smoothThroughputKbps + margin * lastThroughputKbps; + } + } else { + smoothThroughputKbps = 5000; // finetune + } + + return smoothThroughputKbps; + } + + function getQualityFunction(bitrates, functionType) { + var qualityLevelList = []; + var length = bitrates.length; + + if (functionType === "linear") { + for (var i = 0; i < length; i++) { + qualityLevelList.push((1.0 * bitrates[i]) / bitrates[length - 1]); + } + } else { + for (var i = 0; i < length; i++) { + qualityLevelList.push(Math.log(bitrates[i] / bitrates[0])); + } + } + return qualityLevelList; + } + + function setWeightsLinear(m_xi, m_delta, qualityLevelList, segment_duration) { + var num_considered_bitrate = bitratesKbps.length; + var R_max_Mbps = bitratesKbps[num_considered_bitrate - 1]; + var R_o_Mbps = bitratesKbps[num_considered_bitrate - 1]; + var thrp_optimal = bitratesKbps[num_considered_bitrate - 1]; + var last_quality_1_Mbps = bitratesKbps[num_considered_bitrate - 2]; + var optimal_delta_buffer_S = buffer_size * (m_xi - MIN_BUFFER_RATIO); + + var temp_beta_alpha = optimal_delta_buffer_S / segment_duration; + var temp_a = + 2.0 * + Math.exp( + 1 + last_quality_1_Mbps / R_max_Mbps - (2.0 * R_o_Mbps) / R_max_Mbps + ); + var temp_b = + (1 + (temp_beta_alpha * SD) / optimal_delta_buffer_S) / thrp_optimal; + + denominator_exp = Math.exp( + 2 * qualityLevelList[num_considered_bitrate - 1] - 2 * qualityLevelList[0] + ); + alpha = + 1.0 / + (1 + temp_beta_alpha + (R_max_Mbps * temp_b * denominator_exp) / temp_a); + beta = temp_beta_alpha * alpha; + gamma = 1 - alpha - beta; + } + + function setWeightsLogarit( + m_xi, + m_delta, + qualityLevelList, + segment_duration + ) { + var num_considered_bitrate = bitratesKbps.length; + var R_i = bitratesKbps[num_considered_bitrate - 1]; + var R_min = bitratesKbps[0]; + var Q_k = qualityLevelList[qualityLevelList.length - 2]; + var delta_B = m_xi * buffer_size - low_buff_thresS; + denominator_exp = Math.exp( + 2 * qualityLevelList[num_considered_bitrate - 1] - 2 * qualityLevelList[0] + ); + + alpha = + 1 / + (1 + + delta_B / segment_duration + + Math.pow(R_i, 3) / + (m_delta * + Math.pow(R_min, 2) * + bitratesKbps[num_considered_bitrate - 2])); + beta = (alpha * delta_B) / segment_duration; + gamma = 1 - alpha - beta; + } + + function getTotalCost_v3( + bitrates, + qualityIndex, + estimated_throghputKbps, + currentbufferS + ) { + var totalCost; + var bandwidthCost; + var bufferCost; + var qualityCost; + var current_quality_level = qualityLevelList[qualityIndex]; + + var temp = (bitrates[qualityIndex] * 1.0) / estimated_throghputKbps; // bitrate is in bps + var average_quality = 0; + var slice_window = 10; + var length_quality = qualityLevelList.length; + var num_downloaded_segments = selected_quality_index_array.length; + var quality_window = Math.min(slice_window, num_downloaded_segments); + + for (var i = 1; i <= quality_window; i++) { + var m_qualityIndex = getQualityIndexFromBitrate( + selected_quality_index_array[num_downloaded_segments - i], + length_quality + ); + average_quality += qualityLevelList[m_qualityIndex]; + } + + average_quality = (average_quality * 1.0) / quality_window; + + bandwidthCost = temp; + + bufferCost = temp * ((SD * 1.0) / (currentbufferS - low_buff_thresS)); + qualityCost = + Math.exp( + qualityLevelList[length_quality - 1] + + average_quality - + 2 * current_quality_level + ) / denominator_exp; + totalCost = alpha * bandwidthCost + beta * bufferCost + gamma * qualityCost; + + return totalCost; + } + + function onVideoAdaptation() { + availableVideoQualities = player.getAvailableVideoQualities(); + + var length = bitratesKbps.length; + + low_buff_thresS = SD; + if (downloadedData == null || currentBufferS < SD) { + var minBitrate = availableVideoQualities[0].bitrate; + var minQuality = availableVideoQualities[0]; + for (var i = 0; i < availableVideoQualities.length; i++) { + if (availableVideoQualities[i].bitrate < minBitrate) { + minQuality = availableVideoQualities[i]; + minBitrate = availableVideoQualities[i].bitrate; + } + } + downloadedData = minQuality; + return minQuality; + } + selected_quality_index_array.push(downloadedData.bitrate / 1000); + num_downloaded_segments = selected_quality_index_array.length; + + var lowest_cost = Number.MAX_SAFE_INTEGER; + var max_quality = 0; + + smoothThroughputKbps = getSmoothThroughput( + 0.125, + lastThroughputKbps, + smoothThroughputKbps + ); + var estimated_throghputKbps = Math.min( + smoothThroughputKbps, + lastThroughputKbps + ); + + qualityLevelList = getQualityFunction( + bitratesKbps, + document.getElementById("quality_function").value + ); + + for (var i = length - 1; i >= 0; i--) { + if (bitratesKbps[i] < smoothThroughputKbps * (1 + 0.1)) { + max_quality = i; + break; + } + } + + if (max_quality === 0) { + next_selected_quality = max_quality; + } + + if (document.getElementById("quality_function").value == "linear") { + multiplier = 100; + setWeightsLinear(m_xi, m_delta, qualityLevelList, SD); + } else { + multiplier = 10000; + setWeightsLogarit(m_xi, m_delta, qualityLevelList, SD); + } + + for (var i = 1; i <= max_quality; i++) { + var currentTotalCost = Math.round( + multiplier * + getTotalCost_v3( + bitratesKbps, + i, + estimated_throghputKbps, + currentBufferS + ) + ); + if (currentTotalCost <= lowest_cost) { + next_selected_quality = i; + lowest_cost = currentTotalCost; + } + } + + // check if it's suitable to decrease the quality + var threshold_ = 0.2; + if ( + lastBufferS - currentBufferS < lastBufferS * threshold_ && + next_selected_quality < last_selected_quality + ) { + next_selected_quality = last_selected_quality; + } + + last_selected_quality = next_selected_quality; + + var finalDecision; + for (var i = 0; i < availableVideoQualities.length; i++) { + if ( + availableVideoQualities[i].bitrate === + bitratesKbps[next_selected_quality] * 1000 + ) { + finalDecision = availableVideoQualities[i]; + break; + } + } + + downloadedData = finalDecision; + lastBufferS = currentBufferS; + + return finalDecision; + } + + function getQualityIndexFromBitrate(bitrate, bitrates_length) { + for (var i = 0; i < bitrates_length; i++) { + if (bitrate == bitratesKbps[i]) { + return i; + } + } + return 0; + } + + function drawLineChart() { + data = google.visualization.arrayToDataTable(dataset); + var options = { + title: "", + chartArea: { + width: "85%", + }, + curveType: "none", + legend: { + position: "top", + }, + vAxis: { + minValue: 0, + "Bitrates (Mbps)": { label: "Bitrates (Mbps)" }, + "Buffer Length (x10s)": { label: "Buffer Length(x10s)" }, + baselineColor: "#acacac", + gridlines: { + count: 9, + color: "#dcdcdc", + }, + }, + hAxis: { + textPosition: "out", + title: "Segment Number", + baselineColor: "#acacac", + minValue: 0, + gridlines: { + count: 10, + color: "#dcdcdc", + }, + titleTextStyle: { + italic: false, + }, + }, + colors: ["#2c83b9", "#ff931e", "#bf004e"], + }; + + chart.draw(data, options); + } + + window.addEventListener("resize", drawLineChart, true); +})(); From 060702b7d8eb62dac78cdf452b706dd61e152a89 Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 18:04:23 +0100 Subject: [PATCH 02/13] Adjust form --- player/custom-wish-abr/index.html | 4 +--- player/custom-wish-abr/js/script.js | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/player/custom-wish-abr/index.html b/player/custom-wish-abr/index.html index 12303cda..ccb9952a 100644 --- a/player/custom-wish-abr/index.html +++ b/player/custom-wish-abr/index.html @@ -25,14 +25,12 @@ -

-

- +
diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index ee291653..45893ced 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -1,4 +1,6 @@ (function () { + console.log("Starting WISH ABR"); + var qualitySwitches = 0; var buffer_size = 20; var throughputHistory = []; @@ -67,6 +69,10 @@ }, }; + if (location.protocol === "file:") { + document.getElementById("webserver-warning").style.display = "block"; + } + var container = document.getElementById("my-player"); var applyButton = document.getElementById("applyWishConfig"); var player = new bitmovin.player.Player(container, playerConfig); From eedf24be6902a617bb11132a024860ee3c58e4d4 Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 18:13:28 +0100 Subject: [PATCH 03/13] Fix container ID --- player/custom-wish-abr/js/script.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index 45893ced..8197afc8 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -73,7 +73,7 @@ document.getElementById("webserver-warning").style.display = "block"; } - var container = document.getElementById("my-player"); + var container = document.getElementById("player-container"); var applyButton = document.getElementById("applyWishConfig"); var player = new bitmovin.player.Player(container, playerConfig); @@ -113,7 +113,11 @@ availableVideoQualities = player.getAvailableVideoQualities(); currentBufferS = player.getVideoBufferLength(); - function wishmmsp() { + function wishmmsp(bitmovinABRSuggestion) { + console.log( + "Quality switch suggested by Bitmovin player: ", + bitmovinABRSuggestion + ); next_selected_quality = 0; bitratesKbps = availableVideoQualities.map(function (quality) { return quality.bitrate / 1000; From 3eec58faa89e4be8b493a64843cf4f4f04535ede Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 18:32:20 +0100 Subject: [PATCH 04/13] Remove phone frame and use selection --- player/custom-wish-abr/index.html | 4 ++-- player/custom-wish-abr/js/script.js | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/player/custom-wish-abr/index.html b/player/custom-wish-abr/index.html index ccb9952a..4b3aaffe 100644 --- a/player/custom-wish-abr/index.html +++ b/player/custom-wish-abr/index.html @@ -27,13 +27,13 @@
-
+
diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index 8197afc8..73dac618 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -84,7 +84,9 @@ function getUserConfiguration() { var preference = document.getElementById("preferences"); - switch (preference.value) { + var value = preference.value || "balance"; + + switch (value) { case "save_data": m_xi = 1; m_delta = 1; @@ -110,6 +112,7 @@ } applyButton.addEventListener("click", getUserConfiguration); + window.addEventListener("load", getUserConfiguration); availableVideoQualities = player.getAvailableVideoQualities(); currentBufferS = player.getVideoBufferLength(); From 00e983439a9b6550b307e8721e76c1f3cbf074bd Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 18:34:41 +0100 Subject: [PATCH 05/13] Fix rendering data --- player/custom-wish-abr/js/script.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index 73dac618..908ae4ff 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -227,13 +227,14 @@ } // Data for graph rendering + console.log("Download finished"); if ( - data.downloadType.indexOf("media") !== -1 && - data.mimeType.indexOf("video") !== -1 && - data.size > 1000 + event.downloadType.indexOf("media") !== -1 && + event.mimeType.indexOf("video") !== -1 && + event.size > 1000 ) { newValue({ - throughput: Math.round((data.size * 8) / data.downloadTime / 1000), + throughput: Math.round((event.size * 8) / event.downloadTime / 1000), }); } } From 59eedf39eab6a3ab777fabaa6c35f34eafa4abae Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 18:45:15 +0100 Subject: [PATCH 06/13] Chart logs --- player/custom-wish-abr/js/script.js | 1 + 1 file changed, 1 insertion(+) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index 908ae4ff..46fc7a09 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -484,6 +484,7 @@ function drawLineChart() { data = google.visualization.arrayToDataTable(dataset); + console.log("Drawing chart", data, chart); var options = { title: "", chartArea: { From 8a1f647da37eeee59cfd834da57f3b899e0d8c3d Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 18:52:11 +0100 Subject: [PATCH 07/13] Disable condition to draw --- player/custom-wish-abr/js/script.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index 46fc7a09..01e1163c 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -228,15 +228,15 @@ // Data for graph rendering console.log("Download finished"); - if ( - event.downloadType.indexOf("media") !== -1 && - event.mimeType.indexOf("video") !== -1 && - event.size > 1000 - ) { newValue({ throughput: Math.round((event.size * 8) / event.downloadTime / 1000), }); - } + // if ( + // event.downloadType.indexOf("media") !== -1 && + // event.mimeType.indexOf("video") !== -1 && + // event.size > 1000 + // ) { + // } } function getSmoothThroughput( From 25b680da51c2d9183ecc5d82887979291a5bfbbd Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 22:14:33 +0100 Subject: [PATCH 08/13] Fix default number --- player/custom-wish-abr/js/script.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index 01e1163c..a32042d2 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -35,6 +35,7 @@ var data; var chart; + var segmentNumber = 0; var dataset = [ [ "segmentNumber", @@ -74,7 +75,8 @@ } var container = document.getElementById("player-container"); - var applyButton = document.getElementById("applyWishConfig"); + var qfSelect = document.getElementById("quality_function"); + var preferencesSelect = document.getElementById("preferences"); var player = new bitmovin.player.Player(container, playerConfig); var sourceConfig = { @@ -111,7 +113,8 @@ }); } - applyButton.addEventListener("click", getUserConfiguration); + preferencesSelect.addEventListener("change", getUserConfiguration); + qfSelect.addEventListener("change", getUserConfiguration); window.addEventListener("load", getUserConfiguration); availableVideoQualities = player.getAvailableVideoQualities(); currentBufferS = player.getVideoBufferLength(); @@ -228,9 +231,9 @@ // Data for graph rendering console.log("Download finished"); - newValue({ - throughput: Math.round((event.size * 8) / event.downloadTime / 1000), - }); + newValue({ + throughput: Math.round((event.size * 8) / event.downloadTime / 1000), + }); // if ( // event.downloadType.indexOf("media") !== -1 && // event.mimeType.indexOf("video") !== -1 && @@ -484,7 +487,7 @@ function drawLineChart() { data = google.visualization.arrayToDataTable(dataset); - console.log("Drawing chart", data, chart); + console.log("Drawing chart", data, dataset); var options = { title: "", chartArea: { From f746f861fcaaebb491e3fbd2513d68f777378306 Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Tue, 20 Dec 2022 22:40:47 +0100 Subject: [PATCH 09/13] Adjust settings --- player/custom-wish-abr/js/script.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index a32042d2..f47823b4 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -2,7 +2,7 @@ console.log("Starting WISH ABR"); var qualitySwitches = 0; - var buffer_size = 20; + var buffer_size = 40; var throughputHistory = []; var currentQuality = null; var sameRepCount = 0; @@ -63,7 +63,7 @@ tweaks: { file_protocol: true, app_id: "ANY_ID", - max_buffer_level: buffer_size, + // max_buffer_level: buffer_size, }, adaptation: { onVideoAdaptation: wishmmsp, From 9293bbfda3720dd0badb02b3b488d7028c3cf347 Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Wed, 21 Dec 2022 14:40:11 +0100 Subject: [PATCH 10/13] Adjust layout --- player/custom-wish-abr/index.html | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/player/custom-wish-abr/index.html b/player/custom-wish-abr/index.html index 4b3aaffe..b310c055 100644 --- a/player/custom-wish-abr/index.html +++ b/player/custom-wish-abr/index.html @@ -17,6 +17,9 @@
+
+
+
@@ -30,19 +33,14 @@ -
-
-
-
+
+

Bitrate

-
- ${code:demo.js} -
From 0908f8fcabbda612418d9b4d066a2e97c6330268 Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Wed, 21 Dec 2022 14:40:27 +0100 Subject: [PATCH 11/13] Fix buffer size unit --- player/custom-wish-abr/js/script.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index f47823b4..5a7f4970 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -210,7 +210,7 @@ segmentNumber, throughput / 1000, parseInt(chosenQuality) / 1000000, - player.getVideoBufferLength() / 10, + player.getVideoBufferLength(), ]); drawLineChart(); @@ -231,9 +231,11 @@ // Data for graph rendering console.log("Download finished"); - newValue({ - throughput: Math.round((event.size * 8) / event.downloadTime / 1000), - }); + if (event.mimeType.includes("video")) { + newValue({ + throughput: Math.round((event.size * 8) / event.downloadTime / 1000), + }); + } // if ( // event.downloadType.indexOf("media") !== -1 && // event.mimeType.indexOf("video") !== -1 && From 91a7c44d487dc1270450a08a3cfcd5a12717022d Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Wed, 21 Dec 2022 14:56:27 +0100 Subject: [PATCH 12/13] Adjust script --- player/custom-wish-abr/js/script.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index 5a7f4970..bc52c869 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -39,9 +39,9 @@ var dataset = [ [ "segmentNumber", - "Estimated throughput (Mbps)", + "Est. throughput (Mbps)", "Chosen quality (Mbps)", - "Buffer Length (x10s)", + "Buffer Length (sec)", ], [0, 0, 0, 0], ]; @@ -56,17 +56,18 @@ muted: true, autoplay: true, }, - style: { - width: "640px", - height: "480px", - }, tweaks: { file_protocol: true, app_id: "ANY_ID", // max_buffer_level: buffer_size, }, adaptation: { - onVideoAdaptation: wishmmsp, + desktop: { + onVideoAdaptation: wishmmsp, + }, + mobile: { + onVideoAdaptation: wishmmsp, + }, }, }; @@ -191,12 +192,7 @@ }); function newValue(metrics) { - var throughput; - if (metrics.throughput > 5000) { - throughput = 5000; - } else { - throughput = metrics.throughput; - } + var throughput = metrics.throughput; var chosenQuality = player.getDownloadedVideoData().bitrate; From 2925a82361e3fb7a906664349f2183b2ff66cff9 Mon Sep 17 00:00:00 2001 From: Vojtech Zalesky Date: Wed, 12 Apr 2023 16:10:18 +0200 Subject: [PATCH 13/13] Update WISH ABR --- player/custom-wish-abr/js/script.js | 99 +++++++++++++++++------------ 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/player/custom-wish-abr/js/script.js b/player/custom-wish-abr/js/script.js index bc52c869..1e08df47 100644 --- a/player/custom-wish-abr/js/script.js +++ b/player/custom-wish-abr/js/script.js @@ -1,6 +1,28 @@ (function () { console.log("Starting WISH ABR"); + const events = [ + "loadstart", + "suspend", + "abort", + "error", + "emptied", + "stalled", + "loadedmetadata", + "loadeddata", + "canplay", + "canplaythrough", + "playing", + "waiting", + "seeking", + "seeked", + "ended", + "durationchange", + "play", + "pause", + "ratechange", + ]; + var qualitySwitches = 0; var buffer_size = 40; var throughputHistory = []; @@ -108,6 +130,21 @@ .load(sourceConfig) .then(function () { console.log("Successfully loaded Source Config!"); + events.forEach((event) => { + document + .querySelector("#bitmovinplayer-video-player video") + .addEventListener(event, (e) => { + axios + .get( + logURL.replace("%event%", e.type) + + "&noCache=" + + new Date().getTime() + ) + .catch((error) => { + console.log(error); + }); + }); + }); }) .catch(function (reason) { console.log("Error while loading source:", reason); @@ -126,17 +163,17 @@ bitmovinABRSuggestion ); next_selected_quality = 0; - bitratesKbps = availableVideoQualities.map(function (quality) { - return quality.bitrate / 1000; - }); - // sort bitrates - bitratesKbps.sort(function (a, b) { - if (a === Infinity) return 1; - else if (isNaN(a)) return -1; - else return a - b; + availableVideoQualities.sort(function (a, b) { + return a.bitrate - b.bitrate; }); + bitratesKbps = []; + for (var i = 0; i < availableVideoQualities.length; i++) { + if (availableVideoQualities[i].height <= maxResolution) + bitratesKbps.push(availableVideoQualities[i].bitrate / 1000); + } + currentBufferS = player.getVideoBufferLength(); if (!player) { @@ -311,7 +348,7 @@ var num_considered_bitrate = bitratesKbps.length; var R_i = bitratesKbps[num_considered_bitrate - 1]; var R_min = bitratesKbps[0]; - var Q_k = qualityLevelList[qualityLevelList.length - 2]; + var Q_k = bitratesKbps[num_considered_bitrate - 2]; var delta_B = m_xi * buffer_size - low_buff_thresS; denominator_exp = Math.exp( 2 * qualityLevelList[num_considered_bitrate - 1] - 2 * qualityLevelList[0] @@ -321,10 +358,7 @@ 1 / (1 + delta_B / segment_duration + - Math.pow(R_i, 3) / - (m_delta * - Math.pow(R_min, 2) * - bitratesKbps[num_considered_bitrate - 2])); + Math.pow(R_i, 3) / (m_delta * Math.pow(R_min, 2) * Q_K)); beta = (alpha * delta_B) / segment_duration; gamma = 1 - alpha - beta; } @@ -356,11 +390,11 @@ average_quality += qualityLevelList[m_qualityIndex]; } - average_quality = (average_quality * 1.0) / quality_window; + bufferCost = temp * (SD / (currentbufferS - low_buff_thresS)); bandwidthCost = temp; - bufferCost = temp * ((SD * 1.0) / (currentbufferS - low_buff_thresS)); + bufferCost = temp * (SD / (currentbufferS - low_buff_thresS)); qualityCost = Math.exp( qualityLevelList[length_quality - 1] + @@ -373,22 +407,13 @@ } function onVideoAdaptation() { - availableVideoQualities = player.getAvailableVideoQualities(); - - var length = bitratesKbps.length; + const quality_function = document.getElementById("quality_function").value; + const length = bitratesKbps.length; low_buff_thresS = SD; if (downloadedData == null || currentBufferS < SD) { - var minBitrate = availableVideoQualities[0].bitrate; - var minQuality = availableVideoQualities[0]; - for (var i = 0; i < availableVideoQualities.length; i++) { - if (availableVideoQualities[i].bitrate < minBitrate) { - minQuality = availableVideoQualities[i]; - minBitrate = availableVideoQualities[i].bitrate; - } - } - downloadedData = minQuality; - return minQuality; + downloadedData = availableVideoQualities[0]; + return downloadedData; } selected_quality_index_array.push(downloadedData.bitrate / 1000); num_downloaded_segments = selected_quality_index_array.length; @@ -412,7 +437,9 @@ ); for (var i = length - 1; i >= 0; i--) { - if (bitratesKbps[i] < smoothThroughputKbps * (1 + 0.1)) { + if (bitratesKbps[i] < lastThroughputKbps * (1 + 0.1)) { + // MMSP + // if (bitratesKbps[i] < smoothThroughputKbps * (1 + 0.1)) { max_quality = i; break; } @@ -457,21 +484,11 @@ last_selected_quality = next_selected_quality; - var finalDecision; - for (var i = 0; i < availableVideoQualities.length; i++) { - if ( - availableVideoQualities[i].bitrate === - bitratesKbps[next_selected_quality] * 1000 - ) { - finalDecision = availableVideoQualities[i]; - break; - } - } - downloadedData = finalDecision; lastBufferS = currentBufferS; + downloadedData = availableVideoQualities[next_selected_quality]; - return finalDecision; + return availableVideoQualities[next_selected_quality]; } function getQualityIndexFromBitrate(bitrate, bitrates_length) {