一、feng 的框架:
feng 的网络库
feng 使用是轻量级的事件库libev,
二、feng 是如何处理数据的
1、当处理PLAY请求时,feng 调用函数rtp_session_gslist_resume为每一个媒体(track)恢复播放,rtp_session_resume,在该函数,创建了一个线程池,线程数据为1个,(如果多个如何保存有序),线程池的回调是rtp_session_fill_cb,这个线程就是不停地从文件中读出数据,实际是调用钩子avf_read_packet从文件中读出数据,(暂停不知道读了多少数据),读出以后,调用ret = tr->parser->parse(tr, pkt.data, pkt.size);, 实际是调用h264.c注册的钩子,h264_parse, 分为avc格式和常规格式(avc格式起始码是一帧的长度,常规格式起始码是00000001), 我们先看常规格式,即起始码为00000001。
2、接着1,h264_parse其实就是分片,先找到一个nal(找到下一个起始码即可),判断nal的长度,如果小于一个MTU的大小,调用mparser_buffer_write,将数据写入feng 的bufferqueue,实际相当于一个生产者,(这个在PLAY请求后,创建线程池运行的),这么说,bufferqueue(用于数据的一生产多消费), 放入的是nal,即一个元素是nal,
这个小于MTU的nal直接就是rtp的数据了。
3、在PLAY中我们知道,在创建完线程池后,又创建了一个周期性读的rtp_write,这个函数周期性在rtp_write中,读出数据,这个周期性的写的函数可能是在SETUP,创建会话rtp_session_new创建的, 那么执行写的函数就是rtp_write_cb,在这里有足够的数据了,没有足够数据就等一个足够取到数据的时间,有了足够数据,就调用rtp_packet_send(session, buffer);将数据发出,
三、feng 程序运行过程:
1、在incoming.c中feng 调用feng_bind_port函数,生成主线程的监听fd(套接字),并注册回调rtsp_client_incoming_cb,这里使用的是半同步,半异步的reactor;
2、收到客户端的连接请求后,分别为连接返回的客户端fd, 注册可写,可读,异步断开连接,注册的回调为rtsp_write_cb, rtsp_read_cb, client_ev_disconnect_handler, 分别处理写,读,断开的事件;
3、当收到客户端RTSP请求后,回调rtsp_read_cb执行,通过rtsp_sock_read,将数据读出后,这时是rtsp消息(以两个/r/n/r/n结尾),调用RTSP_handler来处理相应的请求,这里面有这个处理方法的指针数据,比较有意思
enum RTSP_method_token {
RTSP_ID_ERROR = ERR_GENERIC,
RTSP_ID_DESCRIBE,
RTSP_ID_ANNOUNCE,
RTSP_ID_GET_PARAMETERS,
RTSP_ID_OPTIONS,
RTSP_ID_PAUSE,
RTSP_ID_PLAY,
RTSP_ID_RECORD,
RTSP_ID_REDIRECT,
RTSP_ID_SETUP,
RTSP_ID_SET_PARAMETER,
RTSP_ID_TEARDOWN
};
static const rtsp_method_function methods[] = {
[RTSP_ID_DESCRIBE] = RTSP_describe,
[RTSP_ID_SETUP] = RTSP_setup,
[RTSP_ID_TEARDOWN] = RTSP_teardown,
[RTSP_ID_OPTIONS] = RTSP_options,
[RTSP_ID_PLAY] = RTSP_play,
[RTSP_ID_PAUSE] = RTSP_pause
};
调用相应的消息的函数,进行处理methods[req->method_id](rtsp, req);
4、处理DESCRIBE 消息,先调用r_find_demuxer找到相应的文件的分离器(用于将包在一起的媒体分离出来),
在r_find_demuxer执行时,先注册钩子,用于不同的流类型的处理,
static const Demuxer *const demuxers[] = {
#ifdef LIVE_STREAMING
&fnc_demuxer_sd,
#endif
&fnc_demuxer_ds,
&fnc_demuxer_avf,
NULL
};
然后来打开r_open_direct相应的文件,如果是avf类型(可能是文件类型),使用avf_init来初始化。
......
(未完待续)