Как сделать видеоплеер HLS из моего собственного DASH-подобного видеоплеера? - PullRequest
0 голосов
/ 29 октября 2018

Я делаю веб-видеоплеер, который может изменять тип видео с 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 width="100px">
    </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 Ответ

0 голосов
/ 29 октября 2018

В iOS вы можете воспроизводить HLS намного проще, поскольку он изначально поддерживается тегом <video>. Вы можете просто сделать <video src="https://example.com/manifest.m3u8">, и это будет работать.

В качестве альтернативы, вы также можете попробовать использовать Media Source Extensions, но написание собственного проигрывателя кажется слишком сложным. Я бы, наверное, посмотрел на hls.js на твоем месте.

...