H265 は著作権の影響を受けており、ブラウザは H265 をサポートしようとしないため、webrtc は H265 のデコードと再生を実装できません。ただし、仕事での帯域幅の問題を解決するには h265 が必要であるため、ブラウザは H265 の再生をサポートしていません。Du Niang から、sctp を送信することで rtp パケットを置き換えることができることを学びました (webrtc のデータ チャネルでは、1. SCTP、2. RTP、3. QUIC の 3 つのプロトコルを使用できます。ここでは最初のプロトコルを学習しましょう)。Web 側はデータを受信し、デコードして表示します。
現在、Google は以下をサポートしています。
WebCodecs(browserInfo.type.toLowerCase()==='chrome' && browserInfo.version >= 107&&(location.protocol==='https:'||location)
MSE(isTypeSupported('video/mp4; codecs=”hev1.1.6.L123.b0″'))
ffmpeg wasm について、この記事では ffmpeg wasm ソフト ソリューションの使用方法について説明します。
SCTP
SCTP の正式名称は Stream Control Transmission Protocol で、デフォルトでポート 5000 を使用する伝送プロトコルで、TCP/IP プロトコル スタックにおける位置付けは TCP や UDP に似ており、TCP と UDP の両方の特性を備えています。
sdpインタラクション
オファー:
a=end-of-candidates
m=application 9 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 23.101.8.213
a=sendrecv
a=sctp-port:5000
a=mid:data
a=ice-ufrag:ePgh
a=ice-pwd:ZURiB67/xs69E76aOa7JDw
a=ice-options:trickle
a=fingerprint:sha-256 EF:7A:50:9C:05:8C:EF:84:4D:72:B2:74:30:BA:FD:82:76:D1:C3:FE:0C:A0:10:43:B8:6C:B2:ED:B3:F7:77:8B
a=setup:actpass
a=candidate:1 1 udp 2013266431 23.101.8.213 41901 typ host
a=end-of-candidates
答え:
m=application 9 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 0.0.0.0
a=sendrecv
a=ice-pwd:518cb4fc626f82bef2ada4e9221dfb50
a=ice-ufrag:d5484fed
a=mid:data
a=setup:active
a=sctp-port:5000
a=max-message-size:1073741823
static void onapplication(void* param, uint32_t track,/* uint32_t object, */int width, int height, const void* extra, size_t bytes)
{
ice_session_t* s = (ice_session_t*)param;
// 6.2. SDP Parameters
static const char* pattern =
"m=application 9 UDP/DTLS/SCTP webrtc-datachanneln"
"a=mid:2n"
"a=sctp-port:5000n"
"a=sendrecvn";
"a=setup:passiven";
strcat((char*)s->app.sender.buffer, pattern);
int n = snprintf(s->app.sdp, sizeof(s->app.sdp), "%s", (char*)s->app.sender.buffer);
n += ice_transport_getsdp(s->avt, s->app.stream, (char*)s->app.sender.buffer + n, sizeof(s->app.sender.buffer) - n);
}
データ送信
DataChannel データは、boringssl によって暗号化され、udp を介してピアに送信されます。データチャネル データとオーディオおよびビデオ データの送信には、同じソケットが使用されます。オーディオおよびビデオ データの送信では、パケット損失を防ぐために NACK および FEC 戦略を使用する RTP プロトコルが使用されますが、DataChannel の最下層では SCTP (ストリーム制御送信プロトコル) プロトコルが使用されます。SCTP は TCP に似ており、フローを備えた信頼性の高いプロトコルです。制御および輻輳制御送信プロトコルに対応しているため、DataChannel データの信頼性の高い送信を実現するために追加の対策は必要ありません。webrtc は、サードパーティのオープン ソース ライブラリ usrsctplib を使用して SCTP プロトコルを実装します。
注: usrsctp は SCTP の UDP カプセル化を提供しますが、これらのメッセージは DTLS でカプセル化され、usrscp 自体ではなく、以前に対話したのと同じ DTLS ソケットによって実際に送受信される必要があります。そのため、AF_CONN メソッドを使用します。
デモ
int ice_transport_send_sctp(struct ice_transport_t* avt, int streamid, uint64_t time, int flags ,const void* data, int bytes)
{
int n = RTP_FIXED_HEADER + bytes;
unsigned char* ptr = (uint8_t*)calloc( 1,n+1);
rtp_header_t header;
memset(&header,0,sizeof(rtp_header_t));
header.timestamp = 1667895211;
header.v = RTP_VERSION;
header.pt = 100;
header.ssrc = bytes;
nbo_write_rtp_header(ptr, &header);
memcpy(ptr + RTP_FIXED_HEADER, data, bytes);//data 265的裸数据
janus_dtls_wrap_sctp_data(avt->dtls, "doc-datachannel", "udp",0, ptr, n);
free(ptr);//后面优化释放
return -1;
}
ウェブ受信
データを受信し、rtp ヘッダーを解析します。
function ReadBig32(array, index) {
return ((array[index] << 24) |
(array[index + 1] << 16) |
(array[index + 2] << 8) |
(array[index + 3]));
}
function initH265DC(pc, player) {
console.log("initH265DC", Date());
bFindFirstKeyFrame = false;
bRecH265 = false;
isKeyFrame = false;
receivet1 = new Date().getTime();
h265DC = pc.createDataChannel("webrtc-datachannel");
// var ctx = canvas.getContext("2d");
console.log("initH265DC0", h265DC);
h265DC.onmessage = function (event) {
// console.log("receive message: ",event.data.slice(12));
//console.log("receive message: ", buf2hex(event.data));
let data = new Uint8Array(event.data);
version = ((data[0] & 0xC0) >>> 6);
padding = ((data[0] & 0x20) >>> 5);
itemCount = (data[0] & 0x1F);
packetType = data[1];
let pts = ReadBig32(data, 4);
let len = ReadBig32(data, 8);
console.log("initH265DC0", version,padding ,itemCount,packetType,pts,len);
//console.log("receive message: ", buf2hex(event.data.split(12)));event.data.byteLength-12
var req = {
t: ksendPlayerVideoFrameReq,
l: len,
d: data.subarray(12).buffer
};
player.postMessage(req, [req.d]);
};
参考
- [1] ギットハブ
- [2] flv-h265.js、webrtc_H265player.juans
- [3] WebAssembly 用の C/C++ プログラミング