Skip to content

Comments

Ingest and publish yuv frames#59

Open
haffi96 wants to merge 4 commits intolivekit:mainfrom
haffi96:raw-nv12-stream
Open

Ingest and publish yuv frames#59
haffi96 wants to merge 4 commits intolivekit:mainfrom
haffi96:raw-nv12-stream

Conversation

@haffi96
Copy link
Contributor

@haffi96 haffi96 commented Feb 15, 2026

A simple example to injest yuv frames and publish to livekit

- RawNv12TcpSource reads fixed-size NV12 frames from TCP
- CLI: --raw-nv12, --raw-width, --raw-height, --raw-fps
- Publish via VideoSource::captureFrame (no decode)
@CLAassistant
Copy link

CLAassistant commented Feb 15, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Collaborator

@xianshijing-lk xianshijing-lk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, it looks good, some comments.

Sorry for being late on reviewing, I was traveling international in the past week.

socket_t connectTcp(const std::string &host, std::uint16_t port) {
#ifdef _WIN32
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not that familiar with the windows API. Do we need to clean up / release the resource explicitly in Stop() as we are calling WSAStartup() in connectTcp() function ?

auto t0 = std::chrono::steady_clock::now();

while (running_.load()) {
std::vector<std::uint8_t> frame(frame_size_);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd better not allocate a new vector of frame() for every run inside the loop.

Move it out, and reserve the frame_size_, like
std::vectorstd::uint8_t buf(frame_size_);

If the frame_size_ can change / increased over time, ideally we can allocate a big enough buffer, otherwise just double the vector if frame_size_ is bigger the size of frames

std::size_t filled = 0;
while (filled < frame_size_ && running_.load()) {
#ifdef _WIN32
int n = recv(fd, reinterpret_cast<char *>(frame.data() + filled),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will recv() block the application forever in some cases?

I wonder if we can add a recv timeout or allow the application to interrupt with ctrl + c ?

#else
ssize_t n = recv(fd, frame.data() + filled, frame_size_ - filled, 0);
#endif
if (n <= 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log it ? I wonder what use case recv will return negative values

YuvFrame out;
out.data = std::move(frame);
out.timestamp_us = ts_us;
callback_(std::move(out));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, replace the whole block with
if (callback_) {
callback_(YuvFrame{std::move(frame), ts_us});
}

void YuvSource::stop() {
running_.store(false);
if (thread_.joinable())
thread_.join();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think .join() will hang the application if the recv() is blocking. Suggestion, set a recv timeout there


YuvSource::~YuvSource() { stop(); }

void YuvSource::start() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it is an example, but wonder if you want the users to call start() / stop() multiple times ?

or they are supposed to be called only once ?

btw, if start() / stop() can be called multiple times WSAStartup(MAKEWORD(2, 2), &wsa) will likely won't work well.

: host_(host), port_(port), width_(width), height_(height), fps_(fps),
callback_(std::move(callback)) {
if (width_ > 0 && height_ > 0) {
frame_size_ = static_cast<std::size_t>(width_) *
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, do we need to validate the width and height to match the expected format

return 1;
}

auto yuvSource = std::make_unique<publish_yuv::YuvSource>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the YuvSource only support raw NV12 ? I wonder if it makes sense to rename it to RawNv12Source or Nv12Source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants