手册Rockchip_Instructions_Linux_MediaServer_CN
rkmedia source的目录结构,其中flow,stream组成为pipe,当前目录下定义了以上的基类。
.
|-- c_api
| `-- osd
|-- ffmpeg
|-- filter
|-- flow
|-- guard
|-- live555
| `-- server
|-- ogg
|-- rkmpp
|-- rknn
|-- rkrga
|-- stream
| |-- audio
| | `-- alsa
| |-- camera
| `-- display
| `-- drm_disp
`-- uvc
配置文件使用json格式。
Pipe表示一路独立的多媒体通道。
Flow表示一路多媒体通道中的一个Source/IO/Sink单元。
Flow是作为上述功能模块的再次封装,便于实现模块间的数据通信。比如有如下业务场景:
v4l2 capture video --> rga --> display
Stream表示FLow使用的处理方法。
${SDK}\external\rkmedia\include\easymedia\flow.h
${SDK}\external\rkmedia\include\easymedia\reflector.h
DECLARE_FACTORY(Flow)
#define DECLARE_FACTORY(PRODUCT) \
class PRODUCT; \
class PRODUCT##Factory { \
public: \
virtual const char *Identifier() const = 0; \
static _API const char *Parse(const char *request); \
virtual std::shared_ptr<PRODUCT> NewProduct(const char *param) = 0; \
bool AcceptRules(const char *rules) const { \
std::map<std::string, std::string> map; \
if (!parse_media_param_map(rules, map)) \
return false; \
return AcceptRules(map); \
} \
virtual bool \
AcceptRules(const std::map<std::string, std::string> &map) const = 0; \
\
protected: \
PRODUCT##Factory() = default; \
virtual ~PRODUCT##Factory() = default; \
\
private: \
PRODUCT##Factory(const PRODUCT##Factory &) = delete; \
PRODUCT##Factory &operator=(const PRODUCT##Factory &) = delete; \
};
基础代理类分析
virtual const char *Identifier() const = 0; 虚函数,字面意思标识
static _API const char *Parse(const char *request); 解析请求字符串
${SDK}\external\tensorflow\tensorflow\contrib\lite\tools\command_line_flags.cc
bool Flag::Parse(const std::string& arg, bool* value_parsing_ok) const {
return ParseFlag(arg, name_, value_hook_, value_parsing_ok);
}
bool ParseFlag(const std::string& arg, const std::string& flag,
const std::function<bool(const std::string&)>& parse_func,
bool* value_parsing_ok) {
*value_parsing_ok = true;
std::string flag_prefix = "--" + flag + "=";
if (arg.find(flag_prefix) != 0) {
return false;
}
bool has_value = (arg.size() >= flag_prefix.size() + 1);
*value_parsing_ok = has_value;
if (has_value) {
*value_parsing_ok = parse_func(arg.substr(flag_prefix.size()));
}
return true;
}
bool parse_media_param_map(const char *param,
std::map<std::string, std::string> &map) {
if (!param)
return false;
std::string token;
std::istringstream tokenStream(param);
while (std::getline(tokenStream, token)) {
std::string key, value;
std::istringstream subTokenStream(token);
if (std::getline(subTokenStream, key, '='))
std::getline(subTokenStream, value);
map[key] = value;
}
return true;
}
字符串转map,用于AcceptRules 规则的承认,AcceptRules(map)的函数由以下宏定义构建,map检索存在规则返回true,否则返回false
#define DEFINE_MEDIA_CHILD_FACTORY_EXTRA(REAL_PRODUCT) \
bool REAL_PRODUCT##Factory::AcceptRules( \
const std::map<std::string, std::string> &map) const { \
static std::list<std::string> expected_data_type_list; \
static std::list<std::string> out_data_type_list; \
static const char *static_keys[] = {KEY_INPUTDATATYPE, KEY_OUTPUTDATATYPE, \
NULL}; \
static const decltype(ExpectedInputDataType) *static_call[] = { \
&ExpectedInputDataType, &OutPutDataType, NULL}; \
static std::list<std::string> *static_list[] = { \
&expected_data_type_list, &out_data_type_list, NULL}; \
const char **keys = static_keys; \
const decltype(ExpectedInputDataType) **call = static_call; \
std::list<std::string> **list = static_list; \
while (*keys) { \
auto it = map.find(*keys); \
if (it == map.end()) { \
if ((*call)()) \
return false; \
} else { \
const std::string &value = it->second; \
if (!value.empty() && \
!has_intersection(value.c_str(), (*call)(), *list)) \
return false; \
} \
++keys; \
++call; \
++list; \
} \
return true; \
}
以上为APP一侧flow 定义分析
#######################################cut here################################
以下rkmedia一侧flow定义
${SDK}\external\rkmedia\src\flow.cc
class FlowCoroutine;
class _API Flow {
public:
// We may need a flow which can be sync and async.
// This make a side effect that sync flow contains superfluous variables
// designed for async implementation.
Flow();
virtual ~Flow();
static const char *GetFlowName() { return nullptr; }
// The GetFlowName interface is occupied by the reflector,
// so GetFlowTag is used to distinguish Flow.
const char *GetFlowTag() { return flow_tag.c_str(); }
void SetFlowTag(std::string tag) { flow_tag = tag; }
// TODO: Right now out_slot_index and in_slot_index is decided by exact
// subclass, automatically get these value or ignore them in future.
bool AddDownFlow(std::shared_ptr<Flow> down, int out_slot_index,
int in_slot_index_of_down);
void RemoveDownFlow(std::shared_ptr<Flow> down);
void SendInput(std::shared_ptr<MediaBuffer> &input, int in_slot_index);
void SetDisable() { enable = false; }
// The Control must be called in the same thread to that create flow
virtual int Control(unsigned long int request _UNUSED, ...) { return -1; }
virtual int SubControl(unsigned long int request, void *arg, int size = 0) {
SubRequest subreq = {request, size, arg};
return Control(S_SUB_REQUEST, &subreq);
}
// get input size for this flow
virtual int GetInputSize() { return 0; }
// The global event hander is the same thread to the born thread of this
// object.
void RegisterEventHandler(std::shared_ptr<Flow> flow, EventHook proc);
void UnRegisterEventHandler();
void EventHookWait();
void NotifyToEventHandler(EventParamPtr param, int type = MESSAGE_TYPE_FIFO);
void NotifyToEventHandler(int id, int type = MESSAGE_TYPE_FIFO);
MessagePtr GetEventMessage();
EventParamPtr GetEventParam(MessagePtr msg);
// Add Link hander For app Link
void SetVideoHandler(LinkVideoHandler hander) {
link_video_handler_ = hander;
}
LinkVideoHandler GetVideoHandler() { return link_video_handler_; }
void SetAudioHandler(LinkAudioHandler hander) {
link_audio_handler_ = hander;
}
LinkAudioHandler GetAudioHandler() { return link_audio_handler_; }
void SetCaptureHandler(LinkCaptureHandler hander) {
link_capture_handler_ = hander;
}
LinkCaptureHandler GetCaptureHandler() { return link_capture_handler_; }
// Add hander For rtsp flow
void SetPlayVideoHandler(PlayVideoHandler handler) {
play_video_handler_ = handler;
}
PlayVideoHandler GetPlayVideoHandler() { return play_video_handler_; }
void SetPlayAudioHandler(PlayAudioHandler handler) {
play_audio_handler_ = handler;
}
PlayAudioHandler GetPlayAudioHandler() { return play_audio_handler_; }
// Add common hander for user
void SetUserCallBack(CallBackHandler handler, UserCallBack callback) {
user_handler_ = handler;
user_callback_ = callback;
}
void SetOutputCallBack(CallBackHandler handler, OutputCallBack callback) {
out_handler_ = handler;
out_callback_ = callback;
}
void SetEventCallBack(CallBackHandler handler, EventCallBack callback) {
event_handler2_ = handler;
event_callback_ = callback;
}
CallBackHandler GetUserHandler() { return user_handler_; }
UserCallBack GetUserCallBack() { return user_callback_; }
// Control the number of executions of threads inside Flow
// _run_times: -1, Endless loop; 0, skip process; > 0, do process cnt.
int SetRunTimes(int _run_times);
int GetRunTimesRemaining();
bool IsAllBuffEmpty();
void DumpBase(std::string &dump_info);
virtual void Dump(std::string &dump_info) { DumpBase(dump_info); }
void StartStream();
int GetCachedBufferNum(unsigned int &total, unsigned int &used);
void ClearCachedBuffers();
protected:
class FlowInputMap {
public:
FlowInputMap(std::shared_ptr<Flow> &f, int i) : flow(f), index_of_in(i) {}
std::shared_ptr<Flow> flow; // weak_ptr?
int index_of_in;
bool operator==(const std::shared_ptr<easymedia::Flow> f) {
return flow == f;
}
};
class FlowMap {
private:
void SetOutputBehavior(const std::shared_ptr<MediaBuffer> &output);
void SetOutputToQueueBehavior(const std::shared_ptr<MediaBuffer> &output);
public:
FlowMap() : valid(false), hold_input(HoldInputMode::NONE) {
assert(list_mtx.valid);
}
FlowMap(FlowMap &&);
void Init(Model m, HoldInputMode hold_in);
bool valid;
HoldInputMode hold_input;
// down flow
void AddFlow(std::shared_ptr<Flow> flow, int index);
void RemoveFlow(std::shared_ptr<Flow> flow);
std::list<FlowInputMap> flows;
ReadWriteLockMutex list_mtx;
std::deque<std::shared_ptr<MediaBuffer>> cached_buffers; // never drop
std::shared_ptr<MediaBuffer> cached_buffer;
decltype(&FlowMap::SetOutputBehavior) set_output_behavior;
};
class Input {
private:
void SyncSendInputBehavior(std::shared_ptr<MediaBuffer> &input);
void ASyncSendInputCommonBehavior(std::shared_ptr<MediaBuffer> &input);
void ASyncSendInputAtomicBehavior(std::shared_ptr<MediaBuffer> &input);
// behavior when input list exceed max_cache_num
bool ASyncFullBlockingBehavior(volatile bool &pred);
bool ASyncFullDropFrontBehavior(volatile bool &pred);
bool ASyncFullDropCurrentBehavior(volatile bool &pred);
public:
Input() : valid(false), flow(nullptr), fetch_block(true) {}
Input(Input &&);
void Init(Flow *f, Model m, int mcn, InputMode im, bool f_block,
std::shared_ptr<FlowCoroutine> fc);
bool valid;
Flow *flow;
Model thread_model;
bool fetch_block;
std::deque<std::shared_ptr<MediaBuffer>> cached_buffers;
ConditionLockMutex mtx;
int max_cache_num;
InputMode mode_when_full;
std::shared_ptr<MediaBuffer> cached_buffer;
SpinLockMutex spin_mtx;
decltype(&Input::SyncSendInputBehavior) send_input_behavior;
decltype(&Input::ASyncFullBlockingBehavior) async_full_behavior;
std::shared_ptr<FlowCoroutine> coroutine;
};
// Can not change the following values after initialize,
// except AddFlow and RemoveFlow.
int out_slot_num;
std::vector<FlowMap> downflowmap;
int input_slot_num;
std::vector<Input> v_input;
std::list<std::shared_ptr<FlowCoroutine>> coroutines;
std::shared_ptr<ConditionLockMutex> source_start_cond_mtx;
int down_flow_num;
bool waite_down_flow;
// source flow
bool SetAsSource(const std::vector<int> &output_slots, FunctionProcess f,
const std::string &mark);
bool InstallSlotMap(SlotMap &map, const std::string &mark,
int exp_process_time);
bool SetOutput(const std::shared_ptr<MediaBuffer> &output,
int out_slot_index);
bool ParseWrapFlowParams(const char *param,
std::map<std::string, std::string> &flow_params,
std::list<std::string> &sub_param_list);
// As sub threads may call the variable of child class,
// we should define this for child class when it deconstruct.
void StopAllThread();
bool IsEnable() { return enable; }
template <int in_index, int out_index>
friend bool void_transaction(Flow *f, MediaBufferVector &input_vector) {
return f->SetOutput(input_vector[in_index], out_index);
}
static const FunctionProcess void_transaction00;
CallBackHandler event_handler2_;
EventCallBack event_callback_;
private:
volatile bool enable;
volatile bool quit;
ConditionLockMutex cond_mtx;
// event handler
std::unique_ptr<EventHandler> event_handler_;
friend class FlowCoroutine;
LinkVideoHandler link_video_handler_;
LinkAudioHandler link_audio_handler_;
LinkCaptureHandler link_capture_handler_;
PlayVideoHandler play_video_handler_;
PlayAudioHandler play_audio_handler_;
CallBackHandler user_handler_;
UserCallBack user_callback_;
CallBackHandler out_handler_;
OutputCallBack out_callback_;
// FlowTag is used to distinguish Flow.
std::string flow_tag;
// Control the number of executions of threads inside Flow
int run_times;
DEFINE_ERR_GETSET()
DECLARE_PART_FINAL_EXPOSE_PRODUCT(Flow)
};