webRTC与MSE(media source extensions)实现p2p视频的一些思路和尝试

2020-12-17 10:59:28

参考地址 webRTC与MSE(media source extensions)实现p2p视频的一些思路和尝试

最近flv.js的事好像有点火,又重新把mse这个东西提上来了。
MSE(media source extensions)是html5的新功能,大致的作用就是可以实现流媒体功能。
如果MSE配合webRTC再加上js的二进制处理,那么可以实现服务器发送视频给其中一个浏览器用户,这个浏览器用户再将视频流传输给其他用户的功能。算是web端在p2p功能上的一种探索吧

思路

server发送视频流的二进制数据给web,web通过webRTC的dataChannel发送给其他web用户。再通过MSE将二进制数据转换成视频流播出。

MSE相关API解析

  • MediaSource.addSourceBuffer()

    • 添加数据到buff

  • MediaSource.removeSourceBuffer()

    • 移除数据

  • MediaSource.endOfStream()

    • 流结束

  • MediaSource.addEventListener()

    • 添加事件响应函数

example

完整的代码见https://github.com/yuyugenius/js_video_p2p_demo
web端使用nodejs,启动方式为 node index.js
由于本人并不是写前端和js的,只是在这方面做了点尝试,所以代码丑陋bug频出请见谅。
由于代码是好几个月前写的,描述不清请见谅
部分webRTC代码来自google

web端获取码流数据

web端获取码流数据可以通过很多方法,我这里是ajax.

/**
 * FILE LOADING
 * method:XMLHttpRequest
 */function get(filename, callback) {
    var request = new XMLHttpRequest();
    request.responseType = 'arraybuffer';
    request.onreadystatechange = function () {
        if (request.readyState == 4 && (request.status == 200 || request.status == 304)) {
            callback(request.response);
        }
    };    var file = 'chunks/' + filename;
    request.open('GET', file, true);
    request.send();
};12345678910111213141516

添加MSE的事件响应

_mediaSource.addEventListener('sourceopen',sourceOpenCallback, false);
_mediaSource.addEventListener('webkitsourceopen',sourceOpenCallback, false);123

设置事件响应,当MSE里有buffer,就播放,这里用的格式是vp8+vorbis,同时开始一个startFileLoading(0)函数。

function sourceOpenCallback() {
    console.log('mediaSource readyState: ' + this.readyState);    // Create the source buffer where we are going to append the
    // new chunks.
    _sourceBuffer = _mediaSource.addSourceBuffer('video/webm; codecs="vp8,vorbis"');    //_sourceBuffer.addEventListener('updateend', loadNextBuffer, false);
    _sourceBuffer.mode = 'sequence';    // Start
    startFileLoading(0);
}1234567891011

_sourceBuffer.mode = 'sequence';mode的值此时表示按队列顺序播放,如果为segments则表示按时间戳播放,具体可以参考html标准的SourceBuffer.
startFileLoading(i)的作用是从服务器上读取视频码流,这里用的是读取视频文件,我的测试代码里预设了一个文件列表。

/**
 * start File LOADING
 */function startFileLoading(i) {
    // Load the chunk
    get(_files[i], function (result) {

        console.log('XMLHttpRequest: loaded', _files[i]);        // Cache the buffer
        _loadedBuffers.push(result);        //if connect with webRTC ,sendMediaData to anothoer user
        if (_isConnection) {            //peer.sendData(result);
            for (var index = 0; index < _peerIndex; index++) {
                peerlist[index].sendData(result);
            }
        }        if (!_sourceBuffer.updating) {            //setTimeout(loadNextBuffer,3000); 
            loadNextBuffer();
        }        if (i == 0) {            // Start playback
            if (video.paused) {
                video.play();
            }
        }

        i++;        if (i == _files.length) {
            i = 0;
        }        // Recursively load next chunk (if one exists)
        if (i < _files.length) {
            setTimeout(function () { startFileLoading(i); }, 9000);            //startFileLoading(i);
        }
    });
}12345678910111213141516171819202122232425262728293031323334353637383940414243

如果当前的web端已经通过webRTC连接了其他web用户,那么就可以通过如果方式将从服务器读取的视频数据发送给其他用户,此时就相当于第二个以后的web用户获得的视频不是从服务器获取,而是从第一个用户那获取。

//if connect with webRTC ,sendMediaData to anothoer userif (_isConnection) {    //peer.sendData(result);
    for (var index = 0; index < _peerIndex; index++) {
        peerlist[index].sendData(result);
    }
}1234567

loadNextBuffer就是读取下一段buffer并且添加进MSE,这样MSE就可以连续不断的播放视频,可以不用等视频完全加载完成才播放,也可以利用这个实现直播效果。

/**
 * video stuff
 * It appends puts the next cached buffer into the source buffer.
 */function loadNextBuffer() {
    if (_loadedBuffers.length) {
        console.log('SourceBuffer: appending', _itemsAppendedToSourceBuffer);        // append the next one into the source buffer.
        _sourceBuffer.appendBuffer(_loadedBuffers.shift());
        _itemsAppendedToSourceBuffer++;
    }    /*
    if (_itemsAppendedToSourceBuffer >= _files.length && !_sourceBuffer.updating) {
        // else close the stream
        _mediaSource.endOfStream();
    }
    */}12345678910111213141516171819

webRTC部分

js/peer.js文件中就是关于webRTC实现的相关操作,有关webRTC部分的实现下篇博客再完善啦


  • 2019-09-03 23:09:17

    Linux下静态库(.a)和动态库(.so) 的生成与使用以及区别

    静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

  • 2019-09-03 23:19:12

    ./configure 的配置和用法

    Linux环境下的软件安装,并不是一件容易的事情;如果通过源代码编译后在安装,当然事情就更为复杂一些;现在安装各种软件的教程都非常普遍;但万变不离其中,对基础知识的扎实掌握,安装各种软件的问题就迎刃而解了。Configure脚本配置工具就是基础之一,它是autoconf的工具的基本应用。

  • 2019-09-04 16:24:17

    Ubuntu apt-get更换为阿里源

    ​进入阿里巴巴开源镜像页面,找到ubuntu,点击后面的帮助,可以看到类似下面的介绍,加入就好。切记下面的第三步。

  • 2019-09-04 16:32:56

    Ubuntu tar 解压缩命令详解

    tar 解压缩命令详解,这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个。下面的参数是根据需要在压缩或解压档案时可选的。

  • 2019-09-04 16:50:35

    CMake入门笔记

    Make是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。

  • 2019-09-05 20:51:15

    在Android上使用FFmpeg压缩视频

    libavcodec-提供了更加全面的编解码实现的合集 libavformat-提供了更加全面的音视频容器格式的封装和解析以及所支持的协议 libavutil-提供了一些公共函数 libavfilter-提供音视频的过滤器,如视频加水印、音频变声等 libavdevice-提供支持众多设备数据的输入与输出,如读取摄像头数据、屏幕录制 libswresample,libavresample-提供音频的重采样工具 libswscale-提供对视频图像进行色彩转换、缩放以及像素格式转换,如图像的YUV转换 libpostproc-多媒体后处理器