Skip to content

Commit 383d588

Browse files
Bring in VideoFrame FrameMetadata from FFI
user_timestamped_video to cpp-example-collection align with latest protos update rust SDK commit copilot cmake suggestions update collection commit
1 parent c457bd4 commit 383d588

16 files changed

Lines changed: 445 additions & 59 deletions

client-sdk-rust

include/livekit/room.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,15 @@ class Room {
270270
VideoFrameCallback callback,
271271
VideoStream::Options opts = {});
272272

273+
/**
274+
* @brief Sets the video frame event callback via
275+
* SubscriptionThreadDispatcher.
276+
*/
277+
void setOnVideoFrameEventCallback(const std::string &participant_identity,
278+
TrackSource source,
279+
VideoFrameEventCallback callback,
280+
VideoStream::Options opts = {});
281+
273282
/**
274283
* @brief Clears the audio frame callback via SubscriptionThreadDispatcher.
275284
*/

include/livekit/room_event_types.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,17 @@ struct AudioEncodingOptions {
307307
std::uint64_t max_bitrate = 0;
308308
};
309309

310+
/**
311+
* Optional RTP packet-trailer features for published video tracks.
312+
*/
313+
struct PacketTrailerFeatures {
314+
/** Embed a user-supplied wall-clock timestamp. */
315+
bool user_timestamp = false;
316+
317+
/** Embed a monotonically increasing frame identifier. */
318+
bool frame_id = false;
319+
};
320+
310321
/**
311322
* Options for publishing a track to the room.
312323
*/
@@ -337,6 +348,9 @@ struct TrackPublishOptions {
337348

338349
/** Enable pre-connect buffering for lower startup latency. */
339350
std::optional<bool> preconnect_buffer;
351+
352+
/** Optional packet-trailer features to enable for published video. */
353+
PacketTrailerFeatures packet_trailer_features{};
340354
};
341355

342356
// ---------------------------------------------------------

include/livekit/subscription_thread_dispatcher.h

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,26 @@ class SubscriptionThreadDispatcher {
159159
VideoFrameCallback callback,
160160
VideoStream::Options opts = {});
161161

162+
/**
163+
* Register or replace a rich video frame event callback for a remote
164+
* subscription.
165+
*
166+
* The callback is keyed by remote participant identity plus \p source.
167+
* If the matching remote video track is already subscribed, \ref Room may
168+
* immediately call \ref handleTrackSubscribed to start a reader.
169+
*
170+
* @param participant_identity Identity of the remote participant.
171+
* @param source Track source to match.
172+
* @param callback Function invoked for each decoded video frame
173+
* event, including optional metadata.
174+
* @param opts Options used when creating the backing
175+
* \ref VideoStream.
176+
*/
177+
void setOnVideoFrameEventCallback(const std::string &participant_identity,
178+
TrackSource source,
179+
VideoFrameEventCallback callback,
180+
VideoStream::Options opts = {});
181+
162182
/**
163183
* Remove an audio callback registration and stop any active reader.
164184
*
@@ -382,7 +402,8 @@ class SubscriptionThreadDispatcher {
382402

383403
/// Stored video callback registration plus stream-construction options.
384404
struct RegisteredVideoCallback {
385-
VideoFrameCallback callback;
405+
VideoFrameCallback legacy_callback;
406+
VideoFrameEventCallback event_callback;
386407
VideoStream::Options options;
387408
};
388409

@@ -413,8 +434,7 @@ class SubscriptionThreadDispatcher {
413434
/// is extracted and returned to the caller for joining outside the lock.
414435
std::thread startVideoReaderLocked(const CallbackKey &key,
415436
const std::shared_ptr<Track> &track,
416-
const VideoFrameCallback &cb,
417-
const VideoStream::Options &opts);
437+
const RegisteredVideoCallback &callback);
418438

419439
/// Extract and close the data reader for a given callback ID, returning its
420440
/// thread. Must be called with \ref lock_ held.

include/livekit/video_source.h

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#pragma once
1818

1919
#include <cstdint>
20+
#include <optional>
2021

2122
#include "livekit/ffi_handle.h"
2223

@@ -36,6 +37,26 @@ enum class VideoRotation {
3637
VIDEO_ROTATION_270 = 270,
3738
};
3839

40+
/**
41+
* Optional packet-trailer metadata carried alongside a video frame.
42+
*
43+
* Each field is independently optional because the corresponding transport
44+
* feature can be negotiated separately.
45+
*/
46+
struct VideoFrameMetadata {
47+
std::optional<std::uint64_t> user_timestamp;
48+
std::optional<std::uint32_t> frame_id;
49+
};
50+
51+
/**
52+
* Capture options for a single outbound video frame.
53+
*/
54+
struct VideoCaptureOptions {
55+
std::int64_t timestamp_us = 0;
56+
VideoRotation rotation = VideoRotation::VIDEO_ROTATION_0;
57+
std::optional<VideoFrameMetadata> metadata;
58+
};
59+
3960
/**
4061
* Represents a real-time video source that can accept frames from the
4162
* application and feed them into the LiveKit core.
@@ -69,14 +90,13 @@ class VideoSource {
6990
/**
7091
* Push a VideoFrame into the FFI video source.
7192
*
72-
* @param frame Video frame to send.
73-
* @param timestamp_us Optional timestamp in microseconds.
74-
* @param rotation Video rotation enum.
75-
* @param timeout_ms Controls waiting behavior:
76-
*
77-
* Notes:
78-
* - Fire-and-forget to send a frame to FFI
79-
* lifetime correctly (e.g., persistent frame pools, GPU buffers, etc.).
93+
* @param frame Video frame to send.
94+
* @param options Timestamp, rotation, and optional metadata for this frame.
95+
*/
96+
void captureFrame(const VideoFrame &frame, const VideoCaptureOptions &options);
97+
98+
/**
99+
* Backward-compatible convenience overload for timestamp + rotation only.
80100
*/
81101
void captureFrame(const VideoFrame &frame, std::int64_t timestamp_us = 0,
82102
VideoRotation rotation = VideoRotation::VIDEO_ROTATION_0);

include/livekit/video_stream.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <condition_variable>
2020
#include <cstdint>
2121
#include <deque>
22+
#include <functional>
2223
#include <memory>
2324
#include <mutex>
2425
#include <optional>
@@ -34,10 +35,17 @@ namespace livekit {
3435
// A single video frame event delivered by VideoStream::read().
3536
struct VideoFrameEvent {
3637
VideoFrame frame;
38+
// WebRTC frame timestamp in microseconds.
39+
// This may be translated onto WebRTC's internal capture-time timeline and
40+
// should not be expected to match application-provided metadata such as
41+
// VideoFrameMetadata::user_timestamp exactly.
3742
std::int64_t timestamp_us;
3843
VideoRotation rotation;
44+
std::optional<VideoFrameMetadata> metadata;
3945
};
4046

47+
using VideoFrameEventCallback = std::function<void(const VideoFrameEvent &)>;
48+
4149
namespace proto {
4250
class FfiEvent;
4351
}

src/room.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
#include "data_track.pb.h"
3333
#include "ffi.pb.h"
3434
#include "ffi_client.h"
35-
#include "lk_log.h"
3635
#include "livekit_ffi.h"
36+
#include "lk_log.h"
3737
#include "room.pb.h"
3838
#include "room_proto_converter.h"
3939
#include "trace/trace_event.h"
@@ -310,7 +310,17 @@ void Room::setOnVideoFrameCallback(const std::string &participant_identity,
310310
VideoStream::Options opts) {
311311
if (subscription_thread_dispatcher_) {
312312
subscription_thread_dispatcher_->setOnVideoFrameCallback(
313-
participant_identity, track_name, std::move(callback), opts);
313+
participant_identity, track_name, std::move(callback), std::move(opts));
314+
}
315+
}
316+
317+
void Room::setOnVideoFrameEventCallback(const std::string &participant_identity,
318+
TrackSource source,
319+
VideoFrameEventCallback callback,
320+
VideoStream::Options opts) {
321+
if (subscription_thread_dispatcher_) {
322+
subscription_thread_dispatcher_->setOnVideoFrameEventCallback(
323+
participant_identity, source, std::move(callback), std::move(opts));
314324
}
315325
}
316326

src/room_proto_converter.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,40 @@
2222

2323
namespace livekit {
2424

25+
namespace {
26+
27+
std::vector<proto::PacketTrailerFeature>
28+
toProto(const PacketTrailerFeatures &features) {
29+
std::vector<proto::PacketTrailerFeature> out;
30+
if (features.user_timestamp) {
31+
out.push_back(proto::PacketTrailerFeature::PTF_USER_TIMESTAMP);
32+
}
33+
if (features.frame_id) {
34+
out.push_back(proto::PacketTrailerFeature::PTF_FRAME_ID);
35+
}
36+
return out;
37+
}
38+
39+
PacketTrailerFeatures
40+
fromProto(const google::protobuf::RepeatedField<int> &features) {
41+
PacketTrailerFeatures out;
42+
for (int feature : features) {
43+
switch (static_cast<proto::PacketTrailerFeature>(feature)) {
44+
case proto::PacketTrailerFeature::PTF_USER_TIMESTAMP:
45+
out.user_timestamp = true;
46+
break;
47+
case proto::PacketTrailerFeature::PTF_FRAME_ID:
48+
out.frame_id = true;
49+
break;
50+
default:
51+
break;
52+
}
53+
}
54+
return out;
55+
}
56+
57+
} // namespace
58+
2559
// --------- enum conversions ---------
2660

2761
ConnectionQuality toConnectionQuality(proto::ConnectionQuality in) {
@@ -340,6 +374,9 @@ proto::TrackPublishOptions toProto(const TrackPublishOptions &in) {
340374
if (in.preconnect_buffer) {
341375
msg.set_preconnect_buffer(*in.preconnect_buffer);
342376
}
377+
for (proto::PacketTrailerFeature feature : toProto(in.packet_trailer_features)) {
378+
msg.add_packet_trailer_features(feature);
379+
}
343380
return msg;
344381
}
345382

@@ -372,6 +409,7 @@ TrackPublishOptions fromProto(const proto::TrackPublishOptions &in) {
372409
if (in.has_preconnect_buffer()) {
373410
out.preconnect_buffer = in.preconnect_buffer();
374411
}
412+
out.packet_trailer_features = fromProto(in.packet_trailer_features());
375413
return out;
376414
}
377415

0 commit comments

Comments
 (0)