feat(streamer): add ffmpeg encoder and mcap recording
This commit is contained in:
@@ -25,9 +25,34 @@ enum class RtmpMode {
|
||||
Domestic,
|
||||
};
|
||||
|
||||
enum class EncoderBackendType {
|
||||
Auto,
|
||||
FFmpeg,
|
||||
GStreamerLegacy,
|
||||
};
|
||||
|
||||
enum class EncoderDeviceType {
|
||||
Auto,
|
||||
Nvidia,
|
||||
Software,
|
||||
};
|
||||
|
||||
enum class McapCompression {
|
||||
None,
|
||||
Lz4,
|
||||
Zstd,
|
||||
};
|
||||
|
||||
struct InputConfig {
|
||||
std::string shm_name{"cvmmap_default"};
|
||||
std::string zmq_endpoint{"ipc:///tmp/cvmmap_default"};
|
||||
std::string uri{"cvmmap://default"};
|
||||
};
|
||||
|
||||
struct EncoderConfig {
|
||||
EncoderBackendType backend{EncoderBackendType::Auto};
|
||||
EncoderDeviceType device{EncoderDeviceType::Auto};
|
||||
CodecType codec{CodecType::H264};
|
||||
std::uint32_t gop{30};
|
||||
std::uint32_t b_frames{0};
|
||||
};
|
||||
|
||||
struct RtmpOutputConfig {
|
||||
@@ -50,10 +75,20 @@ struct OutputsConfig {
|
||||
RtpOutputConfig rtp{};
|
||||
};
|
||||
|
||||
struct McapRecordConfig {
|
||||
bool enabled{false};
|
||||
std::string path{"capture.mcap"};
|
||||
std::string topic{"/camera/video"};
|
||||
std::string frame_id{"camera"};
|
||||
McapCompression compression{McapCompression::Zstd};
|
||||
};
|
||||
|
||||
struct RecordConfig {
|
||||
McapRecordConfig mcap{};
|
||||
};
|
||||
|
||||
struct LatencyConfig {
|
||||
std::size_t queue_size{1};
|
||||
std::uint32_t gop{30};
|
||||
std::uint32_t b_frames{0};
|
||||
bool realtime_sync{true};
|
||||
bool force_idr_on_reset{true};
|
||||
std::uint32_t ingest_max_frames{0};
|
||||
@@ -66,8 +101,9 @@ struct LatencyConfig {
|
||||
struct RuntimeConfig {
|
||||
InputConfig input{};
|
||||
RunMode run_mode{RunMode::Pipeline};
|
||||
CodecType codec{CodecType::H264};
|
||||
EncoderConfig encoder{};
|
||||
OutputsConfig outputs{};
|
||||
RecordConfig record{};
|
||||
LatencyConfig latency{};
|
||||
|
||||
static RuntimeConfig defaults();
|
||||
@@ -76,6 +112,9 @@ struct RuntimeConfig {
|
||||
std::string_view to_string(CodecType codec);
|
||||
std::string_view to_string(RunMode mode);
|
||||
std::string_view to_string(RtmpMode mode);
|
||||
std::string_view to_string(EncoderBackendType backend);
|
||||
std::string_view to_string(EncoderDeviceType device);
|
||||
std::string_view to_string(McapCompression compression);
|
||||
|
||||
std::expected<RuntimeConfig, std::string> parse_runtime_config(int argc, char **argv);
|
||||
std::expected<void, std::string> validate_runtime_config(const RuntimeConfig &config);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "cvmmap_streamer/config/runtime_config.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace cvmmap_streamer::encode {
|
||||
|
||||
struct EncodedAccessUnit {
|
||||
CodecType codec{CodecType::H264};
|
||||
std::uint64_t source_timestamp_ns{0};
|
||||
std::uint64_t stream_pts_ns{0};
|
||||
bool keyframe{false};
|
||||
std::vector<std::uint8_t> annexb_bytes{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "cvmmap_streamer/config/runtime_config.hpp"
|
||||
#include "cvmmap_streamer/encode/encoded_access_unit.hpp"
|
||||
#include "cvmmap_streamer/ipc/contracts.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace cvmmap_streamer::encode {
|
||||
|
||||
struct RawVideoFrame {
|
||||
ipc::FrameInfo info{};
|
||||
std::uint64_t source_timestamp_ns{0};
|
||||
std::span<const std::uint8_t> bytes{};
|
||||
};
|
||||
|
||||
class EncoderBackend {
|
||||
public:
|
||||
virtual ~EncoderBackend() = default;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual std::string_view backend_name() const = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual bool using_hardware() const = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual std::expected<void, std::string> init(const RuntimeConfig &config, const ipc::FrameInfo &frame_info) = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual std::expected<void, std::string> poll() = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual std::expected<void, std::string> push_frame(const RawVideoFrame &frame) = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual std::expected<std::vector<EncodedAccessUnit>, std::string> drain() = 0;
|
||||
|
||||
[[nodiscard]]
|
||||
virtual std::expected<std::vector<EncodedAccessUnit>, std::string> flush() = 0;
|
||||
|
||||
virtual void shutdown() = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
std::expected<std::unique_ptr<EncoderBackend>, std::string> make_encoder_backend(const RuntimeConfig &config);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "cvmmap_streamer/config/runtime_config.hpp"
|
||||
#include "cvmmap_streamer/encode/encoded_access_unit.hpp"
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace cvmmap_streamer::record {
|
||||
|
||||
class McapRecordSink {
|
||||
public:
|
||||
McapRecordSink() = default;
|
||||
~McapRecordSink();
|
||||
|
||||
McapRecordSink(const McapRecordSink &) = delete;
|
||||
McapRecordSink &operator=(const McapRecordSink &) = delete;
|
||||
|
||||
McapRecordSink(McapRecordSink &&other) noexcept;
|
||||
McapRecordSink &operator=(McapRecordSink &&other) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
static std::expected<McapRecordSink, std::string> create(const RuntimeConfig &config);
|
||||
|
||||
[[nodiscard]]
|
||||
std::expected<void, std::string> write_access_unit(const encode::EncodedAccessUnit &access_unit);
|
||||
|
||||
[[nodiscard]]
|
||||
bool is_open() const;
|
||||
|
||||
[[nodiscard]]
|
||||
std::string_view path() const;
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
struct State;
|
||||
State *state_{nullptr};
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user