I'm encoding a video frame with the ffmpeg
libraries, generating an AVPacket
with compressed data.
Thanks to some recent advice here on S/O, I am trying to send that frame over a network using the WebRTC
library libdatachannel
, specifically by adapting the example here:
https://github.com/paullouisageneau/libdatachannel/tree/master/examples/streamer
I am seeing problems inside h264rtppacketizer.cpp
(part of the library, not the example) which are almost certainly to do with how I'm providing the sample data.
(I don't think that this is anything to do with libdatachannel specifically, it will be an issue with what I'm sending)
The example code reads each encoded frame from a file, and populates a sample
by setting the content of the file to the contents of the file:
sample = *reinterpret_cast<vector<byte> *>(&fileContents);
sample
is just a std::vector<byte>;
I have naively copied the contents of an AVPacket->data
pointer into the sample
vector:
sample.resize(pkt->size);
memcpy(sample.data(), pkt->data, pkt->size * sizeof(std::byte));
but the packetizer is falling over when trying to get length values out of that data. Specifically, in the following code, the first iteration gets a length of 1, but the second, looking up index 5, gives 1119887324. This is way too big for my data, which is only 3526 bytes (the whole frame is a single colour so likely to be small once encoded):
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;
}
Here is a dump of
uint32_t length = ntohl(*lengthPtr);
for the first few elements of the message (*lengthPtr
in parentheses):
[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)
(I know I should post a complete sample, I am working on it)
I am fairly sure I am just missing something basic. E.g. am I supposed to do something with the AVPacket
side_data
, does AVPacket have or miss some header info?
If I just fwrite
the pkt->data
for a single frame to disk, I can read the codec information with 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
Update: This issue is solved by changing the H264RtpPacketizer
separator setting from H264RtpPacketizer::Separator::Length
to H264RtpPacketizer::Separator::LongStartSequence
, many thanks to author of libdatachannel paullouisageneau (see answer below)
I have issues related to settings for the libx264
encoder, but can happily encode with h264_nvenc
and h264_mf
The input files of the streamer example for libdatachannel use 32-bit length as NAL unit separator. Therefore, the H264RtpPacketizer
instance is created with H264RtpPacketizer::Separator::Length
.
If I'm not mistaken the ffmpeg output will have 4-byte start sequences as NAL unit prefix instead (which is actually more common), so if you change the packetizer setting to H264RtpPacketizer::Separator::LongStartSequence
it should accept your sample.