| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 | #ifndef JTJAI_MEDIA_RTSP_CLIENT_H#define JTJAI_MEDIA_RTSP_CLIENT_H#include "config.h"#include <string>#include <atomic>#include <memory>#include <chrono>#include <functional>#include <mutex>extern "C" {#include <libavformat/avformat.h>#include <libavcodec/avcodec.h>#include <libavutil/time.h>#include <libswscale/swscale.h>}namespace jtjai_media {enum class RTSPClientStatus {    IDLE,           // 空闲状态    CONNECTING,     // 连接中    CONNECTED,      // 已连接    RECORDING,      // 录制中    FINISHED,       // 完成    ERROR_CONNECT,  // 连接错误    ERROR_RECORD,   // 录制错误    TIMEOUT,        // 超时    CANCELLED,      // 已取消    STREAM_UNAVAILABLE  // 流不可用(快速失败)};struct RTSPClientStats {    int stream_index;    std::string rtsp_url;    std::string output_file;    RTSPClientStatus status;    std::chrono::system_clock::time_point start_time;    std::chrono::system_clock::time_point end_time;    int64_t bytes_received;    int64_t frames_received;    int duration_seconds;    std::string error_message;        RTSPClientStats()        : stream_index(-1)        , status(RTSPClientStatus::IDLE)        , bytes_received(0)        , frames_received(0)        , duration_seconds(0) {}};class RTSPClient {public:    RTSPClient(int stream_index, const StreamConfig& config, const std::string& output_dir);    ~RTSPClient();        // 禁用拷贝构造和赋值    RTSPClient(const RTSPClient&) = delete;    RTSPClient& operator=(const RTSPClient&) = delete;        // 启动录制(阻塞调用)    bool start_recording(int duration_seconds);        // 异步启动录制    void start_recording_async(int duration_seconds,         std::function<void(const RTSPClientStats&)> completion_callback = nullptr);        // 停止录制    void stop_recording();        // 获取当前状态    RTSPClientStatus get_status() const { return stats_.status; }        // 获取统计信息    RTSPClientStats get_stats() const;        // 设置连接超时时间(秒)    void set_connection_timeout(int timeout_seconds) { connection_timeout_ = timeout_seconds; }        // 设置读取超时时间(秒)    void set_read_timeout(int timeout_seconds) { read_timeout_ = timeout_seconds; }        // 检查是否正在运行    bool is_running() const;private:    StreamConfig config_;    std::string output_dir_;    std::string full_output_path_;    mutable std::mutex stats_mutex_;    RTSPClientStats stats_;        // FFmpeg相关    AVFormatContext* input_format_ctx_;    AVFormatContext* output_format_ctx_;    AVStream* input_video_stream_;    AVStream* output_video_stream_;    AVStream* input_audio_stream_;    AVStream* output_audio_stream_;        // 控制标志    std::atomic<bool> should_stop_;    std::atomic<bool> is_recording_;        // 超时设置    int connection_timeout_;    int read_timeout_;        // 私有方法    bool initialize_input();    bool initialize_output();    void cleanup();    bool process_stream(int duration_seconds);    void update_status(RTSPClientStatus status, const std::string& error_msg = "");        // FFmpeg日志回调    static void ffmpeg_log_callback(void* ptr, int level, const char* fmt, va_list vl);        // 超时控制    static int interrupt_callback(void* ctx);    int64_t start_time_us_;    int64_t timeout_us_;};} // namespace jtjai_media#endif // JTJAI_MEDIA_RTSP_CLIENT_H
 |