#pragma once #include #include #include #include #include #include namespace cc { inline cv::VideoWriter make_video_writer( const std::string& path, const cv::Size& frame_size, double fps, const std::string& encoder = "auto", int output_bitrate_kbps = 4000, const std::vector& codec_preference = {}) { namespace fs = std::filesystem; fs::create_directories(fs::path(path).parent_path()); int bitrate_bps = std::max(1, output_bitrate_kbps) * 1000; auto codecs = codec_preference.empty() ? std::vector{"avc1", "mp4v", "H264"} : codec_preference; if (encoder == "auto" || encoder == "gstreamer") { int fps_int = std::max(1, static_cast(std::round(fps))); std::string pipeline = "appsrc ! video/x-raw, format=BGR ! " "video/x-raw,width=" + std::to_string(frame_size.width) + ",height=" + std::to_string(frame_size.height) + ",framerate=" + std::to_string(fps_int) + "/1 ! " "videoconvert ! nvvidconv ! " "video/x-raw(memory:NVMM),format=NV12 ! " "nvv4l2h264enc bitrate=" + std::to_string(bitrate_bps) + " insert-sps-pps=true ! " "h264parse ! mp4mux ! filesink location=" + path; cv::VideoWriter writer(pipeline, cv::CAP_GSTREAMER, 0, fps, frame_size, true); if (writer.isOpened()) { std::cerr << "[video] opened GStreamer hardware encoder (bitrate=" << output_bitrate_kbps << " kbps)\n"; return writer; } writer.release(); if (encoder == "gstreamer") throw std::runtime_error("GStreamer video writer failed for: " + path); } for (const auto& codec : codecs) { int fourcc = cv::VideoWriter::fourcc(codec[0], codec[1], codec[2], codec[3]); cv::VideoWriter writer(path, fourcc, fps, frame_size); if (writer.isOpened()) { std::cerr << "[video] opened OpenCV encoder (codec=" << codec << ")\n"; return writer; } writer.release(); } throw std::runtime_error("Unable to open video writer: " + path); } } // namespace cc