From 8cd96721ff1aceecb7789d8c0f2fde533b11421f Mon Sep 17 00:00:00 2001 From: Evgeny Demchenko Date: Tue, 19 May 2026 16:45:29 +0100 Subject: [PATCH] feat(rtsp-source): packet ring publishing (v0.2 Step 4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cuframes::Publisher (C++ wrapper): добавлены enable_packets(), set_codec_extradata(), publish_packet() методы. - cuframes-rtsp-source: новый CLI flag --enable-packet-ring. При его установке после opening stream — pub.enable_packets(codec_id) + set_codec_extradata из vstream->codecpar->extradata. - В main loop: после av_read_frame, до avcodec_send_packet, packet публикуется в packet ring с конверсией pts/dts из stream_tb в ns, AV_PKT_FLAG_KEY/CORRUPT/DISCONTINUITY → CUFRAMES_PKT_FLAG_*. Тест: cuframes-rtsp-source --rtsp rtsp://... --key cam1 --enable-packet-ring # frames consumer'ы продолжают работать через cuframes:// (как v0.1) # record consumer'ы могут brать packets через cuframes_packets:// (Step 5) Связано: #2, PR #4. --- include/cuframes/cuframes.hpp | 17 ++++++++++ tools/cuframes-rtsp-source/main.cpp | 48 +++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/include/cuframes/cuframes.hpp b/include/cuframes/cuframes.hpp index 846688e..af30b8c 100644 --- a/include/cuframes/cuframes.hpp +++ b/include/cuframes/cuframes.hpp @@ -148,6 +148,23 @@ public: "Publisher::publish_external"); } + /* v0.2 — encoded packet ring */ + void enable_packets(const cuframes_packet_ring_options_t *opts = nullptr) { + check(cuframes_publisher_enable_packets(pub_, opts), + "Publisher::enable_packets"); + } + + void set_codec_extradata(const void *data, size_t size) { + check(cuframes_publisher_set_codec_extradata(pub_, data, size), + "Publisher::set_codec_extradata"); + } + + /* Returns CUFRAMES_OK / negative error code (без throw — caller решает). */ + int publish_packet(const void *data, size_t size, + int64_t pts_ns, int64_t dts_ns, uint32_t flags) noexcept { + return cuframes_publisher_publish_packet(pub_, data, size, pts_ns, dts_ns, flags); + } + cuframes_publisher_t *raw() noexcept { return pub_; } private: diff --git a/tools/cuframes-rtsp-source/main.cpp b/tools/cuframes-rtsp-source/main.cpp index 5eb2ce6..6a67d02 100644 --- a/tools/cuframes-rtsp-source/main.cpp +++ b/tools/cuframes-rtsp-source/main.cpp @@ -60,6 +60,7 @@ struct Args { bool verbose = false; bool realtime = false; // emulate -re у ffmpeg CLI: sleep по pts bool loop = false; // loop input на eof (для file://) + bool enable_packet_ring = false; // v0.2 — публиковать encoded packets }; static void print_usage() { @@ -75,6 +76,8 @@ static void print_usage() { " --ring N cuframes ring size (default 4, range 2..16)\n" " --realtime pace input по PTS (как ffmpeg -re; полезно для файла)\n" " --loop loop input на EOF (только для file://)\n" + " --enable-packet-ring v0.2: дополнительно публиковать encoded packets\n" + " (для consumer'ов с -c:v copy, Frigate record path)\n" " --verbose debug logs\n" " -h, --help this help\n"; } @@ -92,6 +95,7 @@ static int parse_args(int argc, char **argv, Args &a) { else if (s == "--ring") a.ring_size = std::stoi(next()); else if (s == "--realtime") a.realtime = true; else if (s == "--loop") a.loop = true; + else if (s == "--enable-packet-ring") a.enable_packet_ring = true; else if (s == "--verbose") a.verbose = true; else if (s == "-h" || s == "--help") { print_usage(); std::exit(0); } else { std::cerr << "Unknown arg: " << s << "\n"; print_usage(); std::exit(1); } @@ -235,6 +239,27 @@ int main(int argc, char **argv) { << "' ready, ring=" << a.ring_size << " pool_size=" << frame_size << " bytes/frame\n"; + /* v0.2 — encoded packet ring (опционально). */ + if (a.enable_packet_ring) { + cuframes_packet_ring_options_t pkt_opts{}; + pkt_opts.codec_id = (uint32_t)vstream->codecpar->codec_id; + /* остальные поля = 0 → library использует defaults (64 slots, 8MiB, 2MiB max) */ + pub.enable_packets(&pkt_opts); + + if (vstream->codecpar->extradata_size > 0 && vstream->codecpar->extradata) { + pub.set_codec_extradata(vstream->codecpar->extradata, + (size_t)vstream->codecpar->extradata_size); + std::cerr << "[cuframes-src] packet ring active, codec_id=" + << vstream->codecpar->codec_id + << " extradata=" << vstream->codecpar->extradata_size + << " bytes\n"; + } else { + std::cerr << "[cuframes-src] packet ring active, codec_id=" + << vstream->codecpar->codec_id + << " (no extradata in stream — will rely on in-band SPS/PPS)\n"; + } + } + /* Stream для D2D copies */ cudaStream_t stream; cudaStreamCreate(&stream); @@ -279,6 +304,29 @@ int main(int argc, char **argv) { continue; } + /* v0.2 — публикуем encoded packet в packet ring ДО decoder. Это позволяет + * record-consumer'ам брать packet без второго RTSP-подключения к камере. */ + if (a.enable_packet_ring) { + int64_t pkt_pts_ns = (pkt->pts != AV_NOPTS_VALUE) + ? av_rescale_q(pkt->pts, stream_tb, AVRational{1, 1000000000}) + : cuframes::now_ns(); + int64_t pkt_dts_ns = (pkt->dts != AV_NOPTS_VALUE) + ? av_rescale_q(pkt->dts, stream_tb, AVRational{1, 1000000000}) + : pkt_pts_ns; + uint32_t pkt_flags = 0; + if (pkt->flags & AV_PKT_FLAG_KEY) pkt_flags |= CUFRAMES_PKT_FLAG_KEY; + if (pkt->flags & AV_PKT_FLAG_CORRUPT) pkt_flags |= CUFRAMES_PKT_FLAG_CORRUPT; +#ifdef AV_PKT_FLAG_DISCONTINUITY + if (pkt->flags & AV_PKT_FLAG_DISCONTINUITY) pkt_flags |= CUFRAMES_PKT_FLAG_DISCONTINUITY; +#endif + int prr = pub.publish_packet(pkt->data, (size_t)pkt->size, + pkt_pts_ns, pkt_dts_ns, pkt_flags); + if (prr != CUFRAMES_OK && a.verbose) { + std::cerr << "[cuframes-src] publish_packet rc=" << prr + << " size=" << pkt->size << "\n"; + } + } + r = avcodec_send_packet(ctx, pkt); av_packet_unref(pkt); if (r < 0) continue;