如何从我的自定义制作 DASH 之类的视频播放器中制作 HLS 视频播放器?
Posted
技术标签:
【中文标题】如何从我的自定义制作 DASH 之类的视频播放器中制作 HLS 视频播放器?【英文标题】:How to make a HLS video player from my custom make DASH like video player? 【发布时间】:2018-10-28 22:31:32 【问题描述】:我正在制作一个网络视频播放器,它可以将视频类型从 2d 更改为 3d,视频质量从 2160p 更改为 144p,视频 fps 从 60fps 更改为 5fps,音频从英语更改为泰米尔语,字幕从关闭更改为其他语言。我无法让我的视频播放器在ios
上工作,因为IOS
仅支持HLS
。所以我需要指导我如何制作一个HLS
视频播放器,它将像我的DASH
一样的视频播放器完全 操作。我能够让我的DASH
像这个演示中的视频播放器:http://nickdesaulniers.github.io/netfix/demo/bufferAll.html。因此,如果有一个HLS
视频播放器演示显示类似于此演示的内容,我想我会设法制作一个HLS
视频播放器。如果HLS
不能做我的功能,请说明另一种方法。谢谢
这里是完整的示例项目:https://drive.google.com/file/d/156mDgIltBGMkXhx4LZfShxv3A8JrwkNP/view?usp=sharing
我的代码(这是我的原始视频播放器的一个小示例):
<html>
<head>
<meta charset="utf-8"/>
<title>ORIGINAL</title>
</head>
<body>
<video controls style="width: 100%; height: 50%;"></video>
<br>
<select >
</select>
<br>
<div id="current_time_message" style="text-align: center; width: 100%; font-size: 25px;"></div>
<br>
Note: You can only make the chages using the 'select' before the Total Segements Loaded of this sample.
<script>
var set_timer = undefined;
var content_class = new Content_Class();
function Content_Class()
var video_player = document.querySelector("video");
var total_segments = 30,
total_segements_call = false,
current_segment = 0;
var mediaSource = undefined,
sourceBuffer_video = undefined,
sourceBuffer_audio = undefined;
var current_video_type = "2d",
current_video_quality = "2160p",
current_video_frame_rate = "60fps",
current_audio = "english",
current_subtitle = "off",
changed_content = "";
var subtitles_list = [[undefined, "english", "English", "to_be_downloaded"], [undefined, "arabic", "Arabic", "to_be_downloaded"]];
var content_types_list = [["video-type_options", "2d", "3d"], ["video-quality_options", "2160p", "144p"], ["video-fps_options", "60fps", "5fps"], ["audio_options", "tamil", "english"], ["subtitle_options", "off", "english", "arabic"]];
var main_function_CALLS = "appending",
video_append_CALLS = undefined,
audio_append_CALLS = undefined,
seek_bar_time_change_CALLS = true,
re_appendable_check_CALLS = 0,
remove_for_call_change_part2_CALLS = 0,
new_content_CALLS = 0,
time_change_reappend_CALLS = 0;
function url_maker(type, number)
var url = "resources/";
if (type == "video")
return url += type + "/" + current_video_type + "/" + current_video_frame_rate + "/" + current_video_quality + "/" + current_video_type + "_" + current_video_frame_rate + "_" + current_video_quality + "_" + number + ".mp4";
else if (type == "audio")
return url += type + "/" + current_audio + "/" + current_audio + "_" + number + ".mp4";
else
return url += type + "/" + current_subtitle + "/" + current_subtitle + ".txt";
function start()
mediaSource = new MediaSource();
video_player.src = URL.createObjectURL(mediaSource);
for (var x = 0; x < subtitles_list.length; x++)
subtitles_list[x][0] = video_player.addTextTrack("captions", undefined, subtitles_list[x][2]);
mediaSource.addEventListener('sourceopen', function ()
mediaSource.duration = total_segments * 5;
sourceBuffer_video = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64000d"');
sourceBuffer_video.mode = 'sequence';
sourceBuffer_audio = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.5"');
sourceBuffer_audio.mode = 'sequence';
Interactions();
main_function();
);
function Interactions()
var current_time_message = document.getElementById("current_time_message");
var options = document.querySelector("select");
video_player.ontimeupdate = function ()
if (!total_segements_call)
current_time_message.innerHTML = "Video Downloaded from " + new Date(video_player.currentTime * 1000).toISOString().substr(11, 8) + " to " + new Date(current_segment * 1000).toISOString().substr(11, 8);
for (var y=0;y<content_types_list.length;y++)
for (var x=1;x<content_types_list[y].length;x++)
var insert = document.createElement("option");
insert.text = content_types_list[y][0].split("_")[0].toUpperCase() + ": " + content_types_list[y][x].toUpperCase();
options.add(insert);
options.onchange = function()
var text = options.options[options.selectedIndex].value;
text = text.split(": ");
changed_content = text[0].toLowerCase() + "_" + text[1].toLowerCase();
main_function_CALLS = "content changed";
function main_function()
if (main_function_CALLS == "appending")
console.log("----------", current_video_type, current_video_frame_rate, current_video_quality, current_audio, current_subtitle, "----------");
window.clearTimeout(set_timer);
current_segment++;
if (current_segment <= total_segments)
appending_sources(current_segment);
else
var current_time_message = document.getElementById("current_time_message");
current_time_message.innerHTML = "Total segements Loaded";
total_segements_call = true;
else if (main_function_CALLS == "content changed")
change_content();
function appending_sources(x)
video_append_CALLS = false;
audio_append_CALLS = false;
request_xhr (url_maker('video', x), 'arraybuffer', ['video', x, sourceBuffer_video], function (buffer)
sourceBuffer_video.addEventListener('updateend', re_appendable_check);
sourceBuffer_video.appendBuffer(buffer);
video_append_CALLS = true;
);
request_xhr (url_maker('audio', x), 'arraybuffer', ['audio', x, sourceBuffer_audio], function (buffer)
sourceBuffer_audio.addEventListener('updateend', re_appendable_check);
sourceBuffer_audio.appendBuffer(buffer);
audio_append_CALLS = true;
);
function re_appendable_check()
if (++re_appendable_check_CALLS == 2)
sourceBuffer_video.removeEventListener('updateend', re_appendable_check);
sourceBuffer_audio.removeEventListener('updateend', re_appendable_check);
re_appendable_check_CALLS = 0;
video_player_old_time = parseInt((video_player.currentTime / 5).toString().split(".")[0]);
main_function();
function crash_reappend(sourceBuffer, response, number, id)
window.clearTimeout(set_timer);
try
sourceBuffer.addEventListener('updateend', re_appendable_check);
sourceBuffer.appendBuffer(response);
console.log("FINALLY Appended " + id + ": " + number);
catch (err)
sourceBuffer.removeEventListener('updateend', re_appendable_check);
if (main_function_CALLS == "appending")
console.log("Appending Again Failed of " + id + " at " + number);
set_timer = window.setTimeout(function()crash_reappend(sourceBuffer, response, number, id);, 5000);
else
remove_for_call_change(number);
function remove_for_call_change (number)
window.clearTimeout(set_timer);
re_appendable_check_CALLS = 0;
function remove_for_call_change_part2()
if (++remove_for_call_change_part2_CALLS == 2)
sourceBuffer_video.removeEventListener('updateend', remove_for_call_change_part2);
sourceBuffer_audio.removeEventListener('updateend', remove_for_call_change_part2);
remove_for_call_change_part2_CALLS = 0;
current_segment -= 1;
sourceBuffer_video.timestampOffset = current_segment*5;
sourceBuffer_audio.timestampOffset = current_segment*5;
video_player_old_time = parseInt((video_player.currentTime / 5).toString().split(".")[0]);
main_function();
if (!sourceBuffer_audio.updating && !sourceBuffer_video.updating)
re_appendable_check_CALLS = 0;
sourceBuffer_video.removeEventListener('updateend', re_appendable_check);
sourceBuffer_audio.removeEventListener('updateend', re_appendable_check);
sourceBuffer_video.addEventListener('updateend', remove_for_call_change_part2);
sourceBuffer_audio.addEventListener('updateend', remove_for_call_change_part2);
sourceBuffer_video.remove((number*5)-5, number*5);
sourceBuffer_audio.remove((number*5)-5, number*5);
else
set_timer = window.setTimeout(function()remove_for_call_change(number);, 2000);
function request_xhr(url, responsetype, type, input_function)
var xhr = new XMLHttpRequest;
xhr.open('get', url);
xhr.responseType = responsetype;
xhr.onload = function()
try
input_function(xhr.response);
console.log("Appended " + type[0] + ": " + type[1]);
catch (err)
if (responsetype != "")
console.log("Appending Failed of " + type[0] + " at " + type[1]);
type[2].removeEventListener('updateend', re_appendable_check);
crash_reappend(type[2], xhr.response, type[1], type[0]);
else
console.log("SUBTITLE FAILED");
;
xhr.send();
function change_content()
var change_content_type = changed_content.split("_")[0];
var change_content = changed_content.split("_")[1].toLowerCase();
if (change_content_type == "video-type")
if (current_video_type != change_content)
current_video_type = change_content;
new_content();
else main_function_CALLS = "appending";main_function();
else if (change_content_type == "video-quality")
if (current_video_quality != change_content)
current_video_quality = change_content;
new_content();
else main_function_CALLS = "appending";main_function();
else if (change_content_type == "video-fps")
if (current_video_frame_rate != change_content)
current_video_frame_rate = change_content;
new_content();
else main_function_CALLS = "appending";main_function();
else if (change_content_type == "audio")
if (current_audio != change_content)
current_audio = change_content;
new_content();
else main_function_CALLS = "appending";main_function();
else if (change_content_type == "subtitle")
console.log(change_content_type, change_content);
if (current_subtitle != change_content)
current_subtitle = change_content;
subtitle_change();
else main_function_CALLS = "appending";main_function();
function new_content()
function content_changed_reappend()
if (++new_content_CALLS == 2)
sourceBuffer_video.removeEventListener('updateend', content_changed_reappend);
sourceBuffer_audio.removeEventListener('updateend', content_changed_reappend);
new_content_CALLS = 0;
current_segment = parseInt((video_player.currentTime / 5).toString().split(".")[0]);
sourceBuffer_video.timestampOffset = current_segment*5;
sourceBuffer_audio.timestampOffset = current_segment*5;
main_function_CALLS = "appending";
main_function();
sourceBuffer_video.addEventListener('updateend', content_changed_reappend);
sourceBuffer_audio.addEventListener('updateend', content_changed_reappend);
sourceBuffer_video.remove(0, total_segments * 5);
sourceBuffer_audio.remove(0, total_segments * 5);
function subtitle_change()
if (current_subtitle == "off")
for (var x = 0; x < subtitles_list.length; x++)
subtitles_list[x][0].mode = "hidden";
else
for (var x = 0; x < subtitles_list.length; x++)
if (subtitles_list[x][1] == current_subtitle)
if (subtitles_list[x][3] != "downloaded")
var num = x; //wierd problem
subtitles_list[num][0].mode = "showing";
request_xhr(url_maker("subtitle", 0), "", ['subtitle', 0], function(buffer)
var file = buffer.split('\n');
for (var y = 0; y < file.length; y+=2)
subtitles_list[num][0].addCue(new VTTCue(file[y].split(" --> ")[0], file[y].split(" --> ")[1], file[y+1].replace(/\\n/g, '\n')));
);
subtitles_list[num][3] = "downloaded";
else
subtitles_list[x][0].mode = "showing";
else
subtitles_list[x][0].mode = "hidden";
main_function_CALLS = "appending";
main_function();
return
start: start
;
set_timer = window.setTimeout(content_class.start(), 1);
</script>
</body>
</html>
【问题讨论】:
【参考方案1】:在 iOS 中,您可以以更简单的方式获得 HLS 播放,因为它本机受 <video>
tag 支持。您只需执行<video src="https://example.com/manifest.m3u8">
即可。
或者,您也可以在那里尝试使用媒体源扩展,但编写自己的播放器似乎过于复杂。如果我是你,我可能会查看 hls.js。
【讨论】:
我在使用 hls.js 或编写自己的播放器方面没有任何问题或困难。我只是希望我上面播放器的所有功能都可以在 IOS 中使用。如果可以使用 m3u8,请告诉我。以上是关于如何从我的自定义制作 DASH 之类的视频播放器中制作 HLS 视频播放器?的主要内容,如果未能解决你的问题,请参考以下文章