如何从我的自定义制作 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 播放,因为它本机受 &lt;video&gt;tag 支持。您只需执行&lt;video src="https://example.com/manifest.m3u8"&gt; 即可。

或者,您也可以在那里尝试使用媒体源扩展,但编写自己的播放器似乎过于复杂。如果我是你,我可能会查看 hls.js。

【讨论】:

我在使用 hls.js 或编写自己的播放器方面没有任何问题或困难。我只是希望我上面播放器的所有功能都可以在 IOS 中使用。如果可以使用 m3u8,请告诉我。

以上是关于如何从我的自定义制作 DASH 之类的视频播放器中制作 HLS 视频播放器?的主要内容,如果未能解决你的问题,请参考以下文章

iOS中的自定义视频播放器以及下一个视频建议[关闭]

免费或低成本的 mpeg-dash / HLS 视频播放器 [关闭]

如何制作自己的自定义 QNetworkReply?

如何制作自己的简单 MPEG DASH 播放器?

如何制作适用于 IOS 和桌面浏览器的自定义全屏视频按钮?

如何制作自定义音频格式和自定义播放器