如何通过 WebRTC 发送 ffmpeg AVPacket(使用 libdatachannel)
How to send ffmpeg AVPacket through WebRTC (using libdatachannel)
我正在使用 ffmpeg
库对视频帧进行编码,生成具有压缩数据的 AVPacket
。
感谢最近关于 S/O 的一些建议,我正在尝试使用 WebRTC
库 libdatachannel
通过网络发送该帧,特别是通过调整此处的示例:
https://github.com/paullouisageneau/libdatachannel/tree/master/examples/streamer
我在 h264rtppacketizer.cpp
(库的一部分,而不是示例)中看到问题,这几乎可以肯定与我提供样本数据的方式有关。
(我不认为这与 libdatachannel 有任何关系,这与我发送的内容有关)
示例代码从文件中读取每个编码帧,并通过将文件内容设置为文件内容来填充 sample
:
sample = *reinterpret_cast<vector<byte> *>(&fileContents);
sample
只是一个 std::vector<byte>;
我天真地将 AVPacket->data
指针的内容复制到 sample
向量中:
sample.resize(pkt->size);
memcpy(sample.data(), pkt->data, pkt->size * sizeof(std::byte));
但是当试图从该数据中获取长度值时,分包器失败了。
具体来说,在下面的代码中,第一次迭代的长度为 1,但第二次迭代查找索引 5,得到 1119887324。这对我的数据来说太大了,它只有 3526 字节(整个帧是一种颜色编码后可能很小):
while (index < message->size()) {
assert(index + 4 < message->size());
auto lengthPtr = (uint32_t *)(message->data() + index);
uint32_t length = ntohl(*lengthPtr);
auto naluStartIndex = index + 4;
auto naluEndIndex = naluStartIndex + length;
assert(naluEndIndex <= message->size());
auto begin = message->begin() + naluStartIndex;
auto end = message->begin() + naluEndIndex;
nalus->push_back(std::make_shared<NalUnit>(begin, end));
index = naluEndIndex;
}
这是
的转储
uint32_t length = ntohl(*lengthPtr);
对于消息的前几个元素(括号中的*lengthPtr
):
[2022-03-29 15:12:01.182] [info] index 0: 1 (16777216)
[2022-03-29 15:12:01.183] [info] index 1: 359 (1728118784)
[2022-03-29 15:12:01.184] [info] index 2: 91970 (1114046720)
[2022-03-29 15:12:01.186] [info] index 3: 23544512 (3225577217)
[2022-03-29 15:12:01.186] [info] index 4: 1732427807 (532693607)
[2022-03-29 15:12:01.187] [info] index 5: 1119887324 (3693068354)
[2022-03-29 15:12:01.188] [info] index 6: 3223313413 (98312128)
[2022-03-29 15:12:01.188] [info] index 7: 534512896 (384031)
[2022-03-29 15:12:01.188] [info] index 8: 3691315291 (1526728156)
[2022-03-29 15:12:01.189] [info] index 9: 83909537 (2707095557)
[2022-03-29 15:12:01.189] [info] index 10: 6004992 (10574592)
[2022-03-29 15:12:01.190] [info] index 11: 1537277952 (41307)
[2022-03-29 15:12:01.190] [info] index 12: 2701131779 (50331809)
[2022-03-29 15:12:01.192] [info] index 13: 768 (196608)
(我知道我应该 post 一个完整的样本,我正在努力)
我很确定我只是遗漏了一些基本的东西。例如。我应该用 AVPacket
side_data
做些什么吗,AVPacket 是否有或遗漏了一些 header 信息?
如果我只是fwrite
将pkt->data
单帧写入磁盘,我可以用ffprobe
:
读取编解码器信息
Input #0, h264, from 'encodedOut.h264':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 1280x720, 30 tbr, 1200k tbn
更新:通过将 H264RtpPacketizer
分隔符设置从 H264RtpPacketizer::Separator::Length
更改为 H264RtpPacketizer::Separator::LongStartSequence
解决了这个问题,非常感谢 libdatachannel paullouisageneau 的作者(见下面的回答)
我有与 libx264
编码器设置相关的问题,但可以愉快地使用 h264_nvenc
和 h264_mf
进行编码
streamer example for libdatachannel 的输入文件使用 32 位长度作为 NAL 单元分隔符。因此,H264RtpPacketizer
实例是使用 H264RtpPacketizer::Separator::Length
.
创建的
如果我没记错的话,ffmpeg 输出将有 4 字节的起始序列作为 NAL 单元前缀(这实际上更常见),所以如果你将 packetizer 设置更改为 H264RtpPacketizer::Separator::LongStartSequence
它应该接受你的样本。
我正在使用 ffmpeg
库对视频帧进行编码,生成具有压缩数据的 AVPacket
。
感谢最近关于 S/O 的一些建议,我正在尝试使用 WebRTC
库 libdatachannel
通过网络发送该帧,特别是通过调整此处的示例:
https://github.com/paullouisageneau/libdatachannel/tree/master/examples/streamer
我在 h264rtppacketizer.cpp
(库的一部分,而不是示例)中看到问题,这几乎可以肯定与我提供样本数据的方式有关。
(我不认为这与 libdatachannel 有任何关系,这与我发送的内容有关)
示例代码从文件中读取每个编码帧,并通过将文件内容设置为文件内容来填充 sample
:
sample = *reinterpret_cast<vector<byte> *>(&fileContents);
sample
只是一个 std::vector<byte>;
我天真地将 AVPacket->data
指针的内容复制到 sample
向量中:
sample.resize(pkt->size);
memcpy(sample.data(), pkt->data, pkt->size * sizeof(std::byte));
但是当试图从该数据中获取长度值时,分包器失败了。 具体来说,在下面的代码中,第一次迭代的长度为 1,但第二次迭代查找索引 5,得到 1119887324。这对我的数据来说太大了,它只有 3526 字节(整个帧是一种颜色编码后可能很小):
while (index < message->size()) {
assert(index + 4 < message->size());
auto lengthPtr = (uint32_t *)(message->data() + index);
uint32_t length = ntohl(*lengthPtr);
auto naluStartIndex = index + 4;
auto naluEndIndex = naluStartIndex + length;
assert(naluEndIndex <= message->size());
auto begin = message->begin() + naluStartIndex;
auto end = message->begin() + naluEndIndex;
nalus->push_back(std::make_shared<NalUnit>(begin, end));
index = naluEndIndex;
}
这是
的转储uint32_t length = ntohl(*lengthPtr);
对于消息的前几个元素(括号中的*lengthPtr
):
[2022-03-29 15:12:01.182] [info] index 0: 1 (16777216)
[2022-03-29 15:12:01.183] [info] index 1: 359 (1728118784)
[2022-03-29 15:12:01.184] [info] index 2: 91970 (1114046720)
[2022-03-29 15:12:01.186] [info] index 3: 23544512 (3225577217)
[2022-03-29 15:12:01.186] [info] index 4: 1732427807 (532693607)
[2022-03-29 15:12:01.187] [info] index 5: 1119887324 (3693068354)
[2022-03-29 15:12:01.188] [info] index 6: 3223313413 (98312128)
[2022-03-29 15:12:01.188] [info] index 7: 534512896 (384031)
[2022-03-29 15:12:01.188] [info] index 8: 3691315291 (1526728156)
[2022-03-29 15:12:01.189] [info] index 9: 83909537 (2707095557)
[2022-03-29 15:12:01.189] [info] index 10: 6004992 (10574592)
[2022-03-29 15:12:01.190] [info] index 11: 1537277952 (41307)
[2022-03-29 15:12:01.190] [info] index 12: 2701131779 (50331809)
[2022-03-29 15:12:01.192] [info] index 13: 768 (196608)
(我知道我应该 post 一个完整的样本,我正在努力)
我很确定我只是遗漏了一些基本的东西。例如。我应该用
AVPacket
side_data
做些什么吗,AVPacket 是否有或遗漏了一些 header 信息?如果我只是
读取编解码器信息fwrite
将pkt->data
单帧写入磁盘,我可以用ffprobe
:
Input #0, h264, from 'encodedOut.h264':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 1280x720, 30 tbr, 1200k tbn
更新:通过将 H264RtpPacketizer
分隔符设置从 H264RtpPacketizer::Separator::Length
更改为 H264RtpPacketizer::Separator::LongStartSequence
解决了这个问题,非常感谢 libdatachannel paullouisageneau 的作者(见下面的回答)
我有与 libx264
编码器设置相关的问题,但可以愉快地使用 h264_nvenc
和 h264_mf
streamer example for libdatachannel 的输入文件使用 32 位长度作为 NAL 单元分隔符。因此,H264RtpPacketizer
实例是使用 H264RtpPacketizer::Separator::Length
.
如果我没记错的话,ffmpeg 输出将有 4 字节的起始序列作为 NAL 单元前缀(这实际上更常见),所以如果你将 packetizer 设置更改为 H264RtpPacketizer::Separator::LongStartSequence
它应该接受你的样本。