#pragma once #ifdef VP_WITH_FFMPEG #include #include #include #include #include #include #include "ff_common.h" #include "../../utils/vp_semaphore.h" #include "../../utils/vp_utils.h" #include "../../utils/logger/vp_logger.h" namespace vp_nodes { /** * encode and enmux using FFmpeg. * used to encode & enmux network streams or file streams. */ class ff_des: public std::enable_shared_from_this { private: /* core members */ const std::vector m_supported_files = {"mp4", "mkv", "flv", "h265", "h264"}; const std::vector m_supported_protocols = {"rtsp", "rtmp", "udp", "rtp"}; AVFormatContext* m_ofmt_ctx = nullptr; AVCodecContext* m_enc_ctx = nullptr; std::queue m_enmux_packets_q; std::queue m_encode_frames_q; std::mutex m_enmux_packets_m; std::mutex m_encode_frames_m; int m_enmux_packets_q_max_size = 25; int m_encode_frames_q_max_size = 25; std::shared_ptr m_enmux_th = nullptr; std::shared_ptr m_encode_th = nullptr; vp_utils::vp_semaphore m_enmux_semaphore; vp_utils::vp_semaphore m_encode_semaphore; /** * live stream or not for output. */ bool m_live_stream = false; /** * fps of output stream. */ int m_fps = 0; /** * width of output stream in pixels. */ int m_width = 0; /** * height of output stream in pixels. */ int m_height = 0; /** * bitrate of output stream (kbit/s). */ long m_bitrate = 0; /** * codec type name of output stream (strings like `h264/hevc/vp8/...`). */ std::string m_codec_name = ""; /** * pixel format of output stream (strings like `YUV420P/NV12/...`). */ std::string m_pixel_format = ""; /** * max B frames for encode. */ int m_max_b_frames = 0; /** * channel index of output. */ int m_channel_index = -1; /** * type name of hardware used for encode (`none` if no hardware used). */ std::string m_hw_type_name = ""; /** * encoder name used for encoding. */ std::string m_encoder_name = ""; /** * uri for output (rtmp/file/...). */ std::string m_uri = ""; /* inner flags */ int m_inner_stream_index = -1; bool m_enmux_running = false; bool m_encode_running = false; /* inner methods */ void enmux_run(); void encode_run(); void inner_close(); void inner_exit_signal(); std::string print_summary(); bool inner_open(const std::string& uri, int width, int height, int fps, int bitrate, int max_b_frames, const std::string& encoder_name = "", AVPixelFormat sw_pix_fmt = AVPixelFormat::AV_PIX_FMT_YUV420P, AVHWDeviceType hw_type = AVHWDeviceType::AV_HWDEVICE_TYPE_NONE, AVPixelFormat hw_pix_fmt = AVPixelFormat::AV_PIX_FMT_NONE); int hw_encoder_init(AVCodecContext* enc_ctx, const enum AVHWDeviceType hw_type, const enum AVPixelFormat sw_pix_fmt); public: /** * create ff_des instance using initial parameters. * * @param channel_index specify the channel index for output stream. */ ff_des(int channel_index); ~ff_des(); /* disable copy and assignment operations */ ff_des(const ff_des&) = delete; ff_des& operator=(const ff_des&) = delete; /** * try to open ff_des, not thread-safe. * * @param */ bool open(const std::string& uri, int width, int height, int fps, int bitrate, int max_b_frames = 0, const std::string& encoder_name = "", AVPixelFormat sw_pix_fmt = AVPixelFormat::AV_PIX_FMT_YUV420P, AVHWDeviceType hw_type = AVHWDeviceType::AV_HWDEVICE_TYPE_NONE, AVPixelFormat hw_pix_fmt = AVPixelFormat::AV_PIX_FMT_NONE); /** * close ff_des. */ void close(); /** * if working or not. * * @return * true if it is working. */ bool is_opened() const; /** * write the next frame to ff_des, keep as same as cv::VideoWriter. * * @param frame frame to be written. * * @return * true if write successfully. * * @note * return false means: * 1. write too quickly no space prepared, please try to write again. * 2. ff_des not opened yet or not working. */ bool write(const ff_av_frame_ptr& frame); /** * write the next frame to ff_des, support for `<<` operator. * * @param frame frame to be written. * * @return * reference for ff_des. */ ff_des& operator<<(const ff_av_frame_ptr& frame); /** * get fps of output stream in pixels. */ int get_video_fps() const; /** * get width of output stream in pixels. */ int get_video_width() const; /** * get height of output stream in pixels. */ int get_video_height() const; /** * get bitrate of output stream (kbit/s). */ long get_video_bitrate() const; /** * get codec type name of output stream (strings like `h264/hevc/vp8/...`). */ std::string get_video_codec_name() const; /** * get pixel format of output stream (strings like `YUV420P/NV12/...`). */ std::string get_video_pixel_format_name() const; /** * check is live stream or not. */ bool is_live_stream() const; /** * get type name of hardware used for encoding (strings like 'cuda/vaapi', 'none' if no hardware used). */ std::string get_hw_type_name() const; /** * get encoder name used for encoding. */ std::string get_encoder_name() const; /** * get uri of output. */ std::string get_uri() const; /** * get channel index of output. */ int get_channel_index() const; /** * get pointer of encode context from FFmpeg. * used to allocate hardware AVFrame outside of ff_des. */ const AVCodecContext* get_encode_ctx() const; }; } #endif