Files
VideoPipe/nodes/ffio/ff_src.h
2026-06-03 12:43:14 +08:00

246 lines
7.0 KiB
C++

#pragma once
#ifdef VP_WITH_FFMPEG
#include <string>
#include <queue>
#include <vector>
#include <mutex>
#include <algorithm>
#include <functional>
#include "ff_common.h"
#include "../../utils/vp_semaphore.h"
#include "../../utils/vp_utils.h"
#include "../../utils/logger/vp_logger.h"
namespace vp_nodes {
class ff_src;
typedef std::function<void(ff_src_ptr, const std::string&)> ff_src_opened_hooker;
/**
* demux and decode using FFmpeg.
* used to demux & decode network streams or file streams.
*/
class ff_src: public std::enable_shared_from_this<ff_src> {
private:
/* core members */
const std::vector<std::string> m_supported_files = {"mp4", "mkv", "flv", "avi", "h264"};
const std::vector<std::string> m_supported_protocols = {"rtsp", "rtmp", "http", "rtp"};
AVFormatContext* m_ifmt_ctx = nullptr;
AVCodecContext* m_dec_ctx = nullptr;
std::queue<ff_av_packet_ptr> m_demux_packets_q;
std::queue<ff_av_frame_ptr> m_decode_frames_q;
std::mutex m_demux_packets_m;
std::mutex m_decode_frames_m;
int m_demux_packets_q_max_size = 25;
int m_decode_frames_q_max_size = 25;
std::shared_ptr<std::thread> m_demux_th = nullptr;
std::shared_ptr<std::thread> m_decode_th = nullptr;
vp_utils::vp_semaphore m_demux_semaphore;
/**
* live stream or not for input.
*/
bool m_live_stream = false;
/**
* fps of input stream.
*/
int m_fps = 0;
/**
* width of input stream in pixels.
*/
int m_width = 0;
/**
* height of input stream in pixels.
*/
int m_height = 0;
/**
* bitrate of input stream (kbit/s).
*/
long m_bitrate = 0;
/**
* codec type name of input stream (strings like `h264/hevc/vp8/...`).
*/
std::string m_codec_name = "";
/**
* pixel format of input stream (strings like `YUV420P/NV12/...`).
*/
std::string m_pixel_format = "";
/**
* duration of input stream (seconds), only for file stream.
*/
double m_duration = 0.0;
/**
* channel index of input.
*/
int m_channel_index = -1;
/**
* type name of hardware used for decoding (`none` if no hardware used).
*/
std::string m_hw_type_name = "";
/**
* decoder name used for decoding.
*/
std::string m_decoder_name = "";
/**
* uri of input (rtsp/file/...).
*/
std::string m_uri = "";
/* inner flags */
int m_inner_stream_index = -1;
bool m_demux_running = false;
bool m_decode_running = false;
/* inner methods */
void demux_run();
void decode_run();
void inner_close();
std::string print_summary();
bool inner_open(const std::string& uri, const std::string& decoder_name, AVHWDeviceType hw_type);
int hw_decoder_init(AVCodecContext* dec_ctx, const enum AVHWDeviceType type);
/* callbacks */
ff_src_opened_hooker m_src_opened_hooker;
public:
/**
* create ff_src instance using initial parameters.
*
* @param channel_index specify the channel index for input stream.
*/
ff_src(int channel_index);
~ff_src();
/* disable copy and assignment operations */
ff_src(const ff_src&) = delete;
ff_src& operator=(const ff_src&) = delete;
/**
* try to open ff_src, not thread-safe.
*
* @param uri uri to open, url for network streams or file path for file streams.
* @param decoder_name specify the decoder name used for decoding, MUST supported by FFmpeg.
* @param hw_type type of hardware for decoding, MUST supported by FFmpeg.
*
* @note
* if `decoder_name` not specified, ff_src will choose the default decoder accordding to the codec type of input stream.
*/
bool open(const std::string& uri,
const std::string& decoder_name = "",
AVHWDeviceType hw_type = AVHWDeviceType::AV_HWDEVICE_TYPE_NONE);
/**
* close ff_src.
*/
void close();
/**
* if working or not.
*
* @return
* true if it is working.
*/
bool is_opened() const;
/**
* read the next frame from ff_src, keep as same as cv::VideoCapture.
*
* @param frame frame to be returned (return nullptr if read failed).
*
* @return
* true if read successfully.
*
* @note
* return false means:
* 1. read too quickly no data prepared, please try to read again.
* 2. ff_src not opened yet or not working.
*/
bool read(ff_av_frame_ptr& frame);
/**
* read the next frame from ff_src, support for `>>` operator.
*
* @param frame frame to be returned (return nullptr if read failed).
*
* @return
* reference for ff_src.
*/
ff_src& operator>>(ff_av_frame_ptr& frame);
/**
* get fps of input stream.
*/
int get_video_fps() const;
/**
* get width of input stream in pixels.
*/
int get_video_width() const;
/**
* get height of input stream in pixels.
*/
int get_video_height() const;
/**
* get bitrate of input stream (kbit/s).
*/
long get_video_bitrate() const;
/**
* get codec type name of input stream (strings like `h264/hevc/vp8/...`).
*/
std::string get_video_codec_name() const;
/**
* get pixel format of input stream (strings like `YUV420P/NV12/...`).
*/
std::string get_video_pixel_format_name() const;
/**
* get duration of input stream (seconds), only for file stream.
*/
double get_video_duration() const;
/**
* check is live stream or not.
*/
bool is_live_stream() const;
/**
* get type name of hardware used for decoding (strings like 'cuda/vaapi', 'none' if no hardware used).
*/
std::string get_hw_type_name() const;
/**
* get decoder name used for decoding.
*/
std::string get_decoder_name() const;
/**
* get uri of input.
*/
std::string get_uri() const;
/**
* get channel index of input.
*/
int get_channel_index() const;
/**
* set callback for opened event. would be activated every time ff_src opened.
*
* @param src_opened_hooker callback activated when ff_src opened.
*/
void set_src_opened_hooker(ff_src_opened_hooker src_opened_hooker);
};
}
#endif