feat: add publishing & audio to ffi (#46)

- Divide FFI protocol into multiple files
- Audio support
- AV Streams/Sources
- Create tracks
- Use Dashmap to store handles
- Add a capture test
     - Ignored by GHA atm
This commit is contained in:
Théo Monnom
2023-05-08 23:12:37 +02:00
committed by GitHub
parent a5caf12902
commit 1c12e749f2
58 changed files with 3046 additions and 1188 deletions
+86
View File
@@ -0,0 +1,86 @@
syntax = "proto3";
package livekit;
option csharp_namespace = "LiveKit.Proto";
import "handle.proto";
// Allocate a new AudioFrameBuffer
// This is not necessary required because the data structure is fairly simple
// But keep the API consistent with VideoFrame
message AllocAudioBufferRequest {
uint32 sample_rate = 1;
uint32 num_channels = 2;
uint32 samples_per_channel = 3;
}
message AllocAudioBufferResponse { AudioFrameBufferInfo buffer = 1; }
// Create a new AudioStream
// AudioStream is used to receive audio frames from a track
message NewAudioStreamRequest {
FFIHandleId room_handle = 1;
string participant_sid = 2;
string track_sid = 3;
AudioStreamType type = 4;
}
message NewAudioStreamResponse { AudioStreamInfo stream = 1; }
// Create a new AudioSource
message NewAudioSourceRequest { AudioSourceType type = 1; }
message NewAudioSourceResponse { AudioSourceInfo source = 1; }
// Push a frame to an AudioSource
message CaptureAudioFrameRequest {
FFIHandleId source_handle = 1;
FFIHandleId buffer_handle = 2;
}
message CaptureAudioFrameResponse {}
///
/// AudioFrame buffer ///
///
message AudioFrameBufferInfo {
FFIHandleId handle = 1;
uint64 data_ptr = 2; // *const i16
uint32 num_channels = 3;
uint32 sample_rate = 4;
uint32 samples_per_channel = 5;
}
///
/// AudioStream ///
///
enum AudioStreamType {
AUDIO_STREAM_NATIVE = 0;
AUDIO_STREAM_HTML = 1;
}
message AudioStreamInfo {
FFIHandleId handle = 1;
AudioStreamType type = 2;
string track_sid = 3;
}
message AudioStreamEvent {
FFIHandleId handle = 1;
oneof message { AudioFrameReceived frame_received = 2; }
}
message AudioFrameReceived {
AudioFrameBufferInfo frame = 1;
}
///
/// AudioSource ///
///
enum AudioSourceType {
AUDIO_SOURCE_NATIVE = 0;
}
message AudioSourceInfo {
FFIHandleId handle = 1;
AudioSourceType type = 2;
}
+77 -315
View File
@@ -3,347 +3,109 @@ syntax = "proto3";
package livekit;
option csharp_namespace = "LiveKit.Proto";
/// IPC
/// # Safety
/// The foreign language is responsable for disposing an handle
/// Forgetting to dispose the handle may lead to memory leaks
/// Messages in this file can contain an FFIHandle
message FFIHandleId { uint64 id = 1; }
import "handle.proto";
import "track.proto";
import "room.proto";
import "participant.proto";
import "video_frame.proto";
import "audio_frame.proto";
/// This is the input of livekit_ffi_request function
/// We always expect a response (FFIResponse)
message FFIRequest {
oneof message {
InitializeRequest initialize = 1;
// Stop all rooms synchronously (Do we need async here?).
// e.g: This is used for the Unity Editor after each assemblies reload.
DisposeRequest dispose = 2;
ConnectRequest async_connect = 3;
DisconnectRequest async_disconnect = 4;
ToI420Request to_i420 = 5;
ToARGBRequest to_argb = 6;
// Room
ConnectRequest connect = 3;
DisconnectRequest disconnect = 4;
PublishTrackRequest publish_track = 5;
UnpublishTrackRequest unpublish_track = 6;
// Track
CreateVideoTrackRequest create_video_track = 7;
CreateAudioTrackRequest create_audio_track = 8;
// Video
AllocVideoBufferRequest alloc_video_buffer = 9;
NewVideoStreamRequest new_video_stream = 10;
NewVideoSourceRequest new_video_source = 11;
CaptureVideoFrameRequest capture_video_frame = 12;
ToI420Request to_i420 = 13;
ToARGBRequest to_argb = 14;
// Audio
AllocAudioBufferRequest alloc_audio_buffer = 15;
NewAudioStreamRequest new_audio_stream = 16;
NewAudioSourceRequest new_audio_source = 17;
CaptureAudioFrameRequest capture_audio_frame = 18;
}
}
/// This is the output of livekit_ffi_request function.
/// The message field is mostly used to send result of a synchronous operation
/// to the foreign language.
message FFIResponse {
optional uint64 async_id = 1;
oneof message { ToI420Response to_i420 = 2; }
oneof message {
InitializeResponse initialize = 1;
DisposeResponse dispose = 2;
// Room
ConnectResponse connect = 3;
DisconnectResponse disconnect = 4;
PublishTrackResponse publish_track = 5;
UnpublishTrackResponse unpublish_track = 6;
// Track
CreateVideoTrackResponse create_video_track = 7;
CreateAudioTrackResponse create_audio_track = 8;
// Video
AllocVideoBufferResponse alloc_video_buffer = 9;
NewVideoStreamResponse new_video_stream = 10;
NewVideoSourceResponse new_video_source = 11;
CaptureVideoFrameResponse capture_video_frame = 12;
ToI420Response to_i420 = 13;
ToARGBResponse to_argb = 14;
// Audio
AllocAudioBufferResponse alloc_audio_buffer = 15;
NewAudioStreamResponse new_audio_stream = 16;
NewAudioSourceResponse new_audio_source = 17;
CaptureAudioFrameResponse capture_audio_frame = 18;
}
}
/// This message is used to receive the result of asynchronous requests
/// Or to receive events of a Room
message FFIEvent {
// Used if the message is used to send the async result to the foreign
// language
optional uint64 async_id = 1;
oneof message {
ConnectEvent connect_event = 2;
RoomEvent room_event = 3;
TrackEvent track_event = 4;
ParticipantEvent participant_event = 5;
RoomEvent room_event = 1;
TrackEvent track_event = 2;
ParticipantEvent participant_event = 3;
VideoStreamEvent video_stream_event = 4;
AudioStreamEvent audio_stream_event = 5;
ConnectCallback connect = 6;
DisposeCallback dispose = 7;
PublishTrackCallback publish_track = 8;
}
}
// Setup the callback where the foreign language can receive events
// and responses to asynchronous requests
message InitializeRequest { uint64 event_callback_ptr = 1; }
message InitializeResponse {}
message DisposeRequest {}
message ConnectRequest {
string url = 1;
string token = 2;
RoomOptions options = 3;
// Stop all rooms synchronously (Do we need async here?).
// e.g: This is used for the Unity Editor after each assemblies reload.
message DisposeRequest {
bool async = 1;
}
message DisconnectRequest { string room_sid = 1; }
/// Convert a VideoFrameBuffer to a I420Buffer
message ToI420Request {
FFIHandleId buffer = 1; // NOTE: This buffer will be dropped!
message DisposeResponse {
optional FFIAsyncId async_id = 1; // None if sync
}
message ToARGBRequest {
FFIHandleId buffer = 1;
uint64 dst_ptr = 2;
VideoFormatType dst_format = 3;
int32 dst_stride = 4;
int32 dst_width = 5;
int32 dst_height = 6;
message DisposeCallback {
FFIAsyncId async_id = 1;
}
message ConnectEvent {
bool success = 1;
optional RoomInfo room = 2;
}
// TODO(theomonnom): Debug messages (Print handles, forward logs).
message ToI420Response { optional VideoFrameBufferInfo new_buffer = 1; }
/// Models
message Dimension {
uint32 width = 1;
uint32 height = 2;
}
message RoomOptions {
bool auto_subscribe = 1;
bool adaptive_stream = 2;
}
message RoomInfo {
string sid = 1;
string name = 2;
string metadata = 3;
ParticipantInfo local_participant = 4;
repeated ParticipantInfo participants = 5;
}
message ParticipantInfo {
string sid = 1;
string name = 2;
string identity = 3;
string metadata = 4;
repeated TrackPublicationInfo publications = 5;
}
message TrackPublicationInfo {
string sid = 1;
string name = 2;
TrackKind kind = 3;
TrackSource source = 4;
bool simulcasted = 5;
Dimension dimension = 6;
string mime_type = 7;
bool muted = 8;
}
message TrackInfo {
string sid = 1;
string name = 2;
TrackKind kind = 3;
StreamState stream_state = 4;
bool muted = 5;
}
message VideoSinkInfo {
string track_sid = 1;
// More info?
}
enum TrackKind {
KIND_UNKNOWN = 0;
KIND_AUDIO = 1;
KIND_VIDEO = 2;
}
enum TrackSource {
SOURCE_UNKNOWN = 0;
SOURCE_CAMERA = 1;
SOURCE_MICROPHONE = 2;
SOURCE_SCREENSHARE = 3;
SOURCE_SCREENSHARE_AUDIO = 4;
}
enum ConnectionQuality {
QUALITY_POOR = 0;
QUALITY_GOOD = 1;
QUALITY_EXCELLENT = 2;
}
enum ConnectionState {
CONN_DISCONNECTED = 0;
CONN_CONNECTED = 1;
CONN_RECONNECTING = 2;
CONN_UNKNOWN = 3;
}
enum StreamState {
STATE_UNKNOWN = 0;
STATE_ACTIVE = 1;
STATE_PAUSED = 2;
}
enum VideoRotation {
VIDEO_ROTATION_0 = 0;
VIDEO_ROTATION_90 = 1;
VIDEO_ROTATION_180 = 2;
VIDEO_ROTATION_270 = 3;
}
enum DataPacketKind {
KIND_UNRELIABLE = 0;
KIND_RELIABLE = 1;
}
enum VideoFormatType {
FORMAT_ARGB = 0;
FORMAT_BGRA = 1;
FORMAT_ABGR = 2;
FORMAT_RGBA = 3;
}
/// Room Events
message RoomEvent {
string room_sid = 1;
oneof message {
ParticipantConnected participant_connected = 2;
ParticipantDisconnected participant_disconnected = 3;
TrackPublished track_published = 4;
TrackUnpublished track_unpublished = 5;
TrackSubscribed track_subscribed = 6;
TrackUnsubscribed track_unsubscribed = 7;
TrackMuted track_muted = 8;
TrackUnmuted track_unmuted = 9;
ActiveSpeakersChanged speakers_changed = 10;
ConnectionQualityChanged connection_quality_changed = 11;
DataReceived data_received = 12;
ConnectionStateChanged connection_state_changed = 13;
Connected connected = 14;
Disconnected disconnected = 15;
Reconnecting reconnecting = 16;
Reconnected reconnected = 17;
}
}
message ParticipantConnected { ParticipantInfo info = 1; }
message ParticipantDisconnected { ParticipantInfo info = 1; }
message TrackPublished {
string participant_sid = 1;
TrackPublicationInfo publication = 2;
}
message TrackUnpublished {
string participant_sid = 1;
string publication_sid = 2;
}
// Publication isn't needed for subscription events on the FFI
// The FFI will retrieve the publication using the Track sid
message TrackSubscribed {
string participant_sid = 1;
TrackInfo track = 2;
VideoSinkInfo sink = 3;
}
message TrackUnsubscribed {
// The FFI language can dispose/remove the VideoSink here
string participant_sid = 1;
string track_sid = 2;
}
message TrackMuted {
string participant_sid = 1;
string track_sid = 2;
}
message TrackUnmuted {
string participant_sid = 1;
string track_sid = 2;
}
message ActiveSpeakersChanged { repeated string participant_sids = 1; }
message ConnectionQualityChanged {
string participant_sid = 1;
ConnectionQuality quality = 2;
}
message DataReceived {
FFIHandleId handle = 1;
optional string participant_sid = 2;
uint64 data_ptr = 3;
uint64 data_size = 4;
DataPacketKind kind = 5;
}
message ConnectionStateChanged { ConnectionState state = 1; }
message Connected {}
message Disconnected {}
message Reconnecting {}
message Reconnected {}
/// Track Events
message TrackEvent {
string track_sid = 1;
oneof message { FrameReceived frame_received = 2; }
}
message FrameReceived {
VideoFrameInfo frame = 1;
VideoFrameBufferInfo buffer = 2;
}
message VideoFrameInfo {
int64 timestamp = 1;
VideoRotation rotation = 2;
}
message VideoFrameBufferInfo {
FFIHandleId handle = 1;
VideoFrameBufferType buffer_type = 2;
int32 width = 3;
int32 height = 4;
oneof buffer {
PlanarYuvBufferInfo yuv = 5;
BiplanarYuvBufferInfo bi_yuv = 6;
NativeBufferInfo native = 7;
}
}
message PlanarYuvBufferInfo {
int32 chroma_width = 1;
int32 chroma_height = 2;
int32 stride_y = 3;
int32 stride_u = 4;
int32 stride_v = 5;
int32 stride_a = 6;
// *const u8 or *const u16
uint64 data_y_ptr = 7;
uint64 data_u_ptr = 8;
uint64 data_v_ptr = 9;
uint64 data_a_ptr = 10; // nullptr = no alpha
}
message BiplanarYuvBufferInfo {
int32 chroma_width = 1;
int32 chroma_height = 2;
int32 stride_y = 3;
int32 stride_uv = 4;
uint64 data_y_ptr = 5;
uint64 data_uv_ptr = 6;
}
message NativeBufferInfo {
// TODO(theomonnom): Expose graphic context?
}
enum VideoFrameBufferType {
NATIVE = 0;
I420 = 1;
I420A = 2;
I422 = 3;
I444 = 4;
I010 = 5;
NV12 = 6;
WEBGL = 7;
}
/// Participant Events
message ParticipantEvent {
string participant_sid = 1;
oneof message { IsSpeakingChanged speaking_changed = 2; }
}
message IsSpeakingChanged { bool speaking = 1; }
+17
View File
@@ -0,0 +1,17 @@
syntax = "proto3";
package livekit;
option csharp_namespace = "LiveKit.Proto";
/// # Safety
/// The foreign language is responsable for disposing handles
/// Forgetting to dispose the handle may lead to memory leaks
/// Messages in this file can contain an FFIHandle
message FFIHandleId {
uint64 id = 1;
}
/// Link the request/response of an asynchronous call
message FFIAsyncId {
uint64 id = 1;
}
+22
View File
@@ -0,0 +1,22 @@
syntax = "proto3";
package livekit;
option csharp_namespace = "LiveKit.Proto";
//import "handle.proto";
import "track.proto";
message ParticipantInfo {
string sid = 1;
string name = 2;
string identity = 3;
string metadata = 4;
repeated TrackPublicationInfo publications = 5;
}
message ParticipantEvent {
string participant_sid = 1;
oneof message { IsSpeakingChanged speaking_changed = 2; }
}
message IsSpeakingChanged { bool speaking = 1; }
+199
View File
@@ -0,0 +1,199 @@
syntax = "proto3";
package livekit;
option csharp_namespace = "LiveKit.Proto";
import "handle.proto";
import "participant.proto";
import "track.proto";
import "video_frame.proto";
// Connect to a new LiveKit room
message ConnectRequest {
string url = 1;
string token = 2;
RoomOptions options = 3;
}
message ConnectResponse {
FFIAsyncId async_id = 1;
}
message ConnectCallback {
FFIAsyncId async_id = 1;
optional string error = 2;
RoomInfo room = 3;
}
// Disconnect from the a room
message DisconnectRequest { FFIHandleId room_handle = 1; }
message DisconnectResponse { FFIAsyncId async_id = 1; }
message DisconnectCallback { }
// Publish a track to the room
message PublishTrackRequest {
FFIHandleId room_handle = 1;
FFIHandleId track_handle = 2;
TrackPublishOptions options = 3;
}
message PublishTrackResponse {
FFIAsyncId async_id = 1;
}
message PublishTrackCallback {
FFIAsyncId async_id = 1;
optional string error = 2;
TrackPublicationInfo publication = 3;
}
// Unpublish a track from the room
message UnpublishTrackRequest {
FFIHandleId room_handle = 1;
string track_sid = 2;
bool stop_on_unpublish = 3;
}
message UnpublishTrackResponse {
FFIAsyncId async_id = 1;
}
message UnpublishTrackCallback {
optional string error = 1;
}
///
/// Options
///
message VideoEncoding {
uint64 max_bitrate = 1;
double max_framerate = 2;
}
message AudioEncoding {
uint64 max_bitrate = 1;
}
message TrackPublishOptions {
// encodings are optional
VideoEncoding video_encoding = 1;
AudioEncoding audio_encoding = 2;
VideoCodec video_codec = 3;
bool dtx = 4;
bool red = 5;
bool simulcast = 6;
string name = 7;
TrackSource source = 8;
}
message RoomOptions {
bool auto_subscribe = 1;
bool adaptive_stream = 2;
}
///
/// Room
///
enum ConnectionQuality {
QUALITY_POOR = 0;
QUALITY_GOOD = 1;
QUALITY_EXCELLENT = 2;
}
enum ConnectionState {
CONN_DISCONNECTED = 0;
CONN_CONNECTED = 1;
CONN_RECONNECTING = 2;
CONN_UNKNOWN = 3;
}
enum DataPacketKind {
KIND_UNRELIABLE = 0;
KIND_RELIABLE = 1;
}
message RoomEvent {
FFIHandleId room_handle = 1;
oneof message {
ParticipantConnected participant_connected = 2;
ParticipantDisconnected participant_disconnected = 3;
TrackPublished track_published = 4;
TrackUnpublished track_unpublished = 5;
TrackSubscribed track_subscribed = 6;
TrackUnsubscribed track_unsubscribed = 7;
TrackMuted track_muted = 8;
TrackUnmuted track_unmuted = 9;
ActiveSpeakersChanged speakers_changed = 10;
ConnectionQualityChanged connection_quality_changed = 11;
DataReceived data_received = 12;
ConnectionStateChanged connection_state_changed = 13;
Connected connected = 14;
Disconnected disconnected = 15;
Reconnecting reconnecting = 16;
Reconnected reconnected = 17;
}
}
message RoomInfo {
FFIHandleId handle = 1;
string sid = 2;
string name = 3;
string metadata = 4;
ParticipantInfo local_participant = 5;
repeated ParticipantInfo participants = 6;
}
message DataReceived {
FFIHandleId handle = 1;
optional string participant_sid = 2;
uint64 data_ptr = 3;
uint64 data_size = 4;
DataPacketKind kind = 5;
}
// Publication isn't needed for subscription events on the FFI
// The FFI will retrieve the publication using the Track sid
message TrackSubscribed {
string participant_sid = 1;
TrackInfo track = 2;
}
message TrackUnsubscribed {
// The FFI language can dispose/remove the VideoSink here
string participant_sid = 1;
string track_sid = 2;
}
message TrackMuted {
string participant_sid = 1;
string track_sid = 2;
}
message TrackUnmuted {
string participant_sid = 1;
string track_sid = 2;
}
message ParticipantConnected { ParticipantInfo info = 1; }
message ParticipantDisconnected { ParticipantInfo info = 1; }
message TrackPublished {
string participant_sid = 1;
TrackPublicationInfo publication = 2;
}
message TrackUnpublished {
string participant_sid = 1;
string publication_sid = 2;
}
message ActiveSpeakersChanged { repeated string participant_sids = 1; }
message ConnectionQualityChanged {
string participant_sid = 1;
ConnectionQuality quality = 2;
}
message ConnectionStateChanged { ConnectionState state = 1; }
message Connected {}
message Disconnected {}
message Reconnecting {}
message Reconnected {}
+91
View File
@@ -0,0 +1,91 @@
syntax = "proto3";
package livekit;
option csharp_namespace = "LiveKit.Proto";
import "handle.proto";
import "video_frame.proto";
import "audio_frame.proto";
message VideoCaptureOptions {
VideoResolution resolution = 1;
}
message AudioCaptureOptions {
bool echo_cancellation = 1;
bool noise_suppression = 2;
bool auto_gain_control = 3;
}
// Create a new VideoTrack from a VideoSource
message CreateVideoTrackRequest {
string name = 1;
VideoCaptureOptions options = 2;
FFIHandleId source_handle = 3;
}
message CreateVideoTrackResponse {
TrackInfo track = 1;
}
// Create a new AudioTrack from a AudioSource
message CreateAudioTrackRequest {
string name = 1;
AudioCaptureOptions options = 2;
FFIHandleId source_handle = 3;
}
message CreateAudioTrackResponse {
TrackInfo track = 1;
}
///
/// Track
///
message TrackEvent {}
enum TrackKind {
KIND_UNKNOWN = 0;
KIND_AUDIO = 1;
KIND_VIDEO = 2;
}
enum TrackSource {
SOURCE_UNKNOWN = 0;
SOURCE_CAMERA = 1;
SOURCE_MICROPHONE = 2;
SOURCE_SCREENSHARE = 3;
SOURCE_SCREENSHARE_AUDIO = 4;
}
enum StreamState {
STATE_UNKNOWN = 0;
STATE_ACTIVE = 1;
STATE_PAUSED = 2;
}
// TODO(theomonnom): Should we have a separate message whether the track is local or remote?
message TrackPublicationInfo {
string sid = 1;
string name = 2;
TrackKind kind = 3;
TrackSource source = 4;
bool simulcasted = 5;
uint32 width = 6;
uint32 height = 7;
string mime_type = 8;
bool muted = 9;
bool remote = 10;
}
message TrackInfo {
// Tracks created/owned by the client will have a handle
FFIHandleId opt_handle = 1;
string sid = 2;
string name = 3;
TrackKind kind = 4;
StreamState stream_state = 5;
bool muted = 6;
bool remote = 7;
}
+198
View File
@@ -0,0 +1,198 @@
syntax = "proto3";
package livekit;
option csharp_namespace = "LiveKit.Proto";
import "handle.proto";
// Allocate a new VideoFrameBuffer
message AllocVideoBufferRequest {
VideoFrameBufferType type = 1; // Only I420 is supported atm
uint32 width = 2;
uint32 height = 3;
}
message AllocVideoBufferResponse { VideoFrameBufferInfo buffer = 1; }
// Create a new VideoStream
// VideoStream is used to receive video frames from a track
message NewVideoStreamRequest {
FFIHandleId room_handle = 1;
string participant_sid = 2;
string track_sid = 3;
VideoStreamType type = 4;
}
message NewVideoStreamResponse { VideoStreamInfo stream = 1; }
// Create a new VideoSource
// VideoSource is used to send video frame to a track
message NewVideoSourceRequest { VideoSourceType type = 1; }
message NewVideoSourceResponse { VideoSourceInfo source = 1; }
// Push a frame to a VideoSource
message CaptureVideoFrameRequest {
FFIHandleId source_handle = 1;
VideoFrameInfo frame = 2;
FFIHandleId buffer_handle = 3;
}
message CaptureVideoFrameResponse {}
// Convert a RGBA frame to a I420 YUV frame
// Or convert another YUV frame format to I420
message ToI420Request {
bool flip_y = 1;
oneof from {
ARGBBufferInfo argb = 2;
FFIHandleId buffer = 3;
}
}
message ToI420Response { VideoFrameBufferInfo buffer = 1; }
// Convert a YUV frame to a RGBA frame
// Only I420 is supported atm
message ToARGBRequest {
FFIHandleId buffer = 1;
uint64 dst_ptr = 2;
VideoFormatType dst_format = 3;
uint32 dst_stride = 4;
uint32 dst_width = 5;
uint32 dst_height = 6;
bool flip_y = 7;
}
message ToARGBResponse {}
///
/// VideoFrame buffers ///
///
message VideoResolution {
uint32 width = 1;
uint32 height = 2;
double frame_rate = 3;
}
enum VideoCodec {
VP8 = 0;
H264 = 1;
AV1 = 2;
}
enum VideoRotation {
VIDEO_ROTATION_0 = 0;
VIDEO_ROTATION_90 = 1;
VIDEO_ROTATION_180 = 2;
VIDEO_ROTATION_270 = 3;
}
enum VideoFormatType {
FORMAT_ARGB = 0;
FORMAT_BGRA = 1;
FORMAT_ABGR = 2;
FORMAT_RGBA = 3;
}
enum VideoFrameBufferType {
NATIVE = 0;
I420 = 1;
I420A = 2;
I422 = 3;
I444 = 4;
I010 = 5;
NV12 = 6;
WEBGL = 7;
}
message ARGBBufferInfo {
uint64 ptr = 1;
VideoFormatType format = 2;
uint32 stride = 3;
uint32 width = 4;
uint32 height = 5;
}
message VideoFrameInfo {
int64 timestamp = 1;
VideoRotation rotation = 2;
}
message VideoFrameBufferInfo {
FFIHandleId handle = 1;
VideoFrameBufferType buffer_type = 2;
uint32 width = 3;
uint32 height = 4;
oneof buffer {
PlanarYuvBufferInfo yuv = 5;
BiplanarYuvBufferInfo bi_yuv = 6;
NativeBufferInfo native = 7;
}
}
message PlanarYuvBufferInfo {
uint32 chroma_width = 1;
uint32 chroma_height = 2;
uint32 stride_y = 3;
uint32 stride_u = 4;
uint32 stride_v = 5;
uint32 stride_a = 6;
// *const u8 or *const u16
uint64 data_y_ptr = 7;
uint64 data_u_ptr = 8;
uint64 data_v_ptr = 9;
uint64 data_a_ptr = 10; // nullptr = no alpha
}
message BiplanarYuvBufferInfo {
uint32 chroma_width = 1;
uint32 chroma_height = 2;
uint32 stride_y = 3;
uint32 stride_uv = 4;
uint64 data_y_ptr = 5;
uint64 data_uv_ptr = 6;
}
message NativeBufferInfo {
// TODO(theomonnom): Expose graphic context?
}
///
/// VideoStream ///
///
enum VideoStreamType {
VIDEO_STREAM_NATIVE = 0;
VIDEO_STREAM_WEBGL = 1;
VIDEO_STREAM_HTML = 2;
}
message VideoStreamInfo {
FFIHandleId handle = 1;
VideoStreamType type = 2;
string track_sid = 3;
}
message VideoStreamEvent {
FFIHandleId handle = 1;
oneof message { VideoFrameReceived frame_received = 2; }
}
message VideoFrameReceived {
VideoFrameInfo frame = 1;
VideoFrameBufferInfo buffer = 2;
}
///
/// VideoSource ///
///
enum VideoSourceType {
VIDEO_SOURCE_NATIVE = 0;
}
message VideoSourceInfo {
// # SAFETY
// This handle must not be dropped if a track is currently using it
FFIHandleId handle = 1;
VideoSourceType type = 2;
}