feat: try implement djs voice + video (v12)
This commit is contained in:
126
src/client/voice/dispatcher/AnnexBDispatcher.js
Normal file
126
src/client/voice/dispatcher/AnnexBDispatcher.js
Normal file
@@ -0,0 +1,126 @@
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
Credit: https://github.com/dank074/Discord-video-stream
|
||||
The use of video streaming in this library is an incomplete implementation with many bugs, primarily aimed at lazy users.
|
||||
The video streaming features in this library are sourced from https://github.com/dank074/Discord-video-stream.
|
||||
|
||||
Please use the @dank074/discord-video-stream library to access all advanced and professional features,
|
||||
along with comprehensive support. I will not actively fix bugs related to streaming and encourage everyone to
|
||||
use https://github.com/dank074/Discord-video-stream for stable and smooth streaming.
|
||||
|
||||
To reiterate: This is an incomplete implementation of the library https://github.com/dank074/Discord-video-stream.
|
||||
|
||||
Thanks to dank074 and longnguyen2004 for implementing new codecs (H264, H265).
|
||||
Thanks to mrjvs for discovering how Discord transmits data and the VP8 codec.
|
||||
|
||||
Please use the @dank074/discord-video-stream library for the best support.
|
||||
*/
|
||||
|
||||
const { Buffer } = require('buffer');
|
||||
const VideoDispatcher = require('./VideoDispatcher');
|
||||
const { H264Helpers, H265Helpers } = require('../player/processing/AnnexBNalSplitter');
|
||||
|
||||
class AnnexBDispatcher extends VideoDispatcher {
|
||||
constructor(player, highWaterMark = 12, streams, fps, nalFunctions) {
|
||||
super(player, highWaterMark, streams, fps);
|
||||
this._nalFunctions = nalFunctions;
|
||||
}
|
||||
|
||||
codecCallback(frame) {
|
||||
let accessUnit = frame;
|
||||
const nalus = [];
|
||||
let offset = 0;
|
||||
|
||||
// Extract NALUs from the access unit
|
||||
while (offset < accessUnit.length) {
|
||||
const naluSize = accessUnit.readUInt32BE(offset);
|
||||
offset += 4;
|
||||
const nalu = accessUnit.subarray(offset, offset + naluSize);
|
||||
nalus.push(nalu);
|
||||
offset += naluSize;
|
||||
}
|
||||
|
||||
nalus.forEach((nalu, index) => {
|
||||
const isLastNal = index === nalus.length - 1;
|
||||
|
||||
if (nalu.length <= this.mtu) {
|
||||
// If NALU size is within MTU, send it directly
|
||||
this._playChunk(Buffer.concat([this.createHeaderExtension(), nalu]), index + 1 === nalus.length);
|
||||
} else {
|
||||
// If NALU size exceeds MTU, fragment it
|
||||
const [naluHeader, naluData] = this._nalFunctions.splitHeader(nalu);
|
||||
const dataFragments = this.partitionVideoData(naluData);
|
||||
|
||||
dataFragments.forEach((data, fragmentIndex) => {
|
||||
const isFirstPacket = fragmentIndex === 0;
|
||||
const isFinalPacket = fragmentIndex === dataFragments.length - 1;
|
||||
const markerBit = isLastNal && isFinalPacket; // Is last packet ?
|
||||
|
||||
this._playChunk(
|
||||
Buffer.concat([
|
||||
this.createHeaderExtension(),
|
||||
this.makeFragmentationUnitHeader(isFirstPacket, isFinalPacket, naluHeader),
|
||||
data,
|
||||
]),
|
||||
markerBit,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class H264Dispatcher extends AnnexBDispatcher {
|
||||
constructor(player, highWaterMark = 12, streams, fps) {
|
||||
super(player, highWaterMark, streams, fps, H264Helpers);
|
||||
}
|
||||
|
||||
makeFragmentationUnitHeader(isFirstPacket, isLastPacket, naluHeader) {
|
||||
const nal0 = naluHeader[0];
|
||||
const fuPayloadHeader = Buffer.alloc(2);
|
||||
const nalType = H264Helpers.getUnitType(naluHeader);
|
||||
const fnri = nal0 & 0xe0;
|
||||
|
||||
fuPayloadHeader[0] = 0x1c | fnri;
|
||||
|
||||
if (isFirstPacket) {
|
||||
fuPayloadHeader[1] = 0x80 | nalType;
|
||||
} else if (isLastPacket) {
|
||||
fuPayloadHeader[1] = 0x40 | nalType;
|
||||
} else {
|
||||
fuPayloadHeader[1] = nalType;
|
||||
}
|
||||
|
||||
return fuPayloadHeader;
|
||||
}
|
||||
}
|
||||
|
||||
class H265Dispatcher extends AnnexBDispatcher {
|
||||
constructor(player, highWaterMark = 12, streams, fps) {
|
||||
super(player, highWaterMark, streams, fps, H265Helpers);
|
||||
}
|
||||
|
||||
makeFragmentationUnitHeader(isFirstPacket, isLastPacket, naluHeader) {
|
||||
const fuIndicatorHeader = Buffer.allocUnsafe(3);
|
||||
naluHeader.copy(fuIndicatorHeader);
|
||||
const nalType = H265Helpers.getUnitType(naluHeader);
|
||||
|
||||
fuIndicatorHeader[0] = (fuIndicatorHeader[0] & 0b10000001) | (49 << 1);
|
||||
|
||||
if (isFirstPacket) {
|
||||
fuIndicatorHeader[2] = 0x80 | nalType;
|
||||
} else if (isLastPacket) {
|
||||
fuIndicatorHeader[2] = 0x40 | nalType;
|
||||
} else {
|
||||
fuIndicatorHeader[2] = nalType;
|
||||
}
|
||||
|
||||
return fuIndicatorHeader;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
H264Dispatcher,
|
||||
H265Dispatcher,
|
||||
};
|
||||
Reference in New Issue
Block a user