webrtc-sys 0.3.39

Unsafe bindings to libwebrtc
Documentation
/*
 * Copyright 2026 LiveKit, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef LIVEKIT_JETSON_MMAPI_ENCODER_H_
#define LIVEKIT_JETSON_MMAPI_ENCODER_H_

#include <linux/videodev2.h>

#include <cstdint>
#include <optional>
#include <string>
#include <vector>

class NvVideoEncoder;

namespace livekit {

enum class JetsonCodec : uint8_t { kH264, kH265, kAV1 };

class JetsonMmapiEncoder {
 public:
  explicit JetsonMmapiEncoder(JetsonCodec codec);
  ~JetsonMmapiEncoder();

  static bool IsSupported();
  static bool IsCodecSupported(JetsonCodec codec);

  bool Initialize(int width,
                  int height,
                  int framerate,
                  int bitrate_bps,
                  int keyframe_interval);
  void Destroy();
  bool IsInitialized() const;

  bool Encode(const uint8_t* src_y,
              int stride_y,
              const uint8_t* src_u,
              int stride_u,
              const uint8_t* src_v,
              int stride_v,
              bool force_keyframe,
              std::vector<uint8_t>* encoded,
              bool* is_keyframe);

  // NV12 input: full-resolution luma plane (Y) + interleaved chroma plane (UV).
  // This matches Jetson MMAPI encoder output-plane expectations on most Jetsons.
  bool EncodeNV12(const uint8_t* src_y,
                  int stride_y,
                  const uint8_t* src_uv,
                  int stride_uv,
                  bool force_keyframe,
                  std::vector<uint8_t>* encoded,
                  bool* is_keyframe);

  // Zero-copy DMA buffer encode: pass an NvBufSurface DMA fd directly to the
  // encoder output plane via V4L2_MEMORY_DMABUF. No pixel data is copied.
  bool EncodeDmaBuf(int dmabuf_fd,
                    bool force_keyframe,
                    std::vector<uint8_t>* encoded,
                    bool* is_keyframe);

  void SetRates(int framerate, int bitrate_bps);
  void SetKeyframeInterval(int keyframe_interval);

 private:
  bool CreateEncoder();
  bool ConfigureEncoder();
  void ConfigureAv1HeadersWithFrame();
  bool ConfigureAv1Encoder();
  bool SetupPlanes();
  bool QueueCaptureBuffers();
  bool StartStreaming();
  void StopStreaming();
  bool QueueOutputBuffer(const uint8_t* src_y,
                         int stride_y,
                         const uint8_t* src_u,
                         int stride_u,
                         const uint8_t* src_v,
                         int stride_v);
  bool QueueOutputBufferNV12(const uint8_t* src_y,
                             int stride_y,
                             const uint8_t* src_uv,
                             int stride_uv);
  bool QueueOutputBufferDmaBuf(int dmabuf_fd);
  bool SetupPlanesDmaBuf();
  bool DequeueCaptureBuffer(std::vector<uint8_t>* encoded, bool* is_keyframe);
  bool DequeueOutputBuffer();
  bool ForceKeyframe();

  static std::optional<std::string> FindEncoderDevice();
  static uint32_t CodecToV4L2PixFmt(JetsonCodec codec);
  static uint32_t CodecToV4L2FallbackPixFmt(JetsonCodec codec);

  JetsonCodec codec_;
  NvVideoEncoder* encoder_ = nullptr;
  bool initialized_ = false;
  bool streaming_ = false;

  int width_ = 0;
  int height_ = 0;
  int framerate_ = 0;
  int bitrate_bps_ = 0;
  int keyframe_interval_ = 0;

  int output_buffer_count_ = 0;
  int capture_buffer_count_ = 0;
  int next_output_index_ = 0;
  int output_y_stride_ = 0;
  int output_u_stride_ = 0;
  int output_v_stride_ = 0;
  bool output_is_nv12_ = false;
  bool use_dmabuf_input_ = false;
  bool dmabuf_planes_setup_ = false;

  // Cached NvBufSurface plane metadata for DmaBuf encode path.
  // Populated on the first QueueOutputBufferDmaBuf call to avoid
  // repeated NvBufSurfaceFromFd lookups (which trigger "Wrong buffer
  // index" warnings on some JetPack versions).
  bool dmabuf_meta_cached_ = false;
  uint32_t dmabuf_num_planes_ = 0;
  uint32_t dmabuf_plane_bytesused_[VIDEO_MAX_PLANES] = {};

  // Whether NvBufSurfaceSyncForDevice works for MMAP plane fds.
  // Set to false on the first failure so we stop attempting (and
  // spamming) on JetPack versions where MMAP fds aren't recognised
  // by the NvBufSurface API.  V4L2 MMAP + qBuffer handles cache
  // coherency on its own, so skipping the explicit sync is safe.
  bool mmap_sync_supported_ = true;
};

}  // namespace livekit

#endif  // LIVEKIT_JETSON_MMAPI_ENCODER_H_