ffserver + hls + ts 循环缓冲区


http_receive_data:
 如果feed_write_index >= FileMaxSize,则回绕循环写,覆盖先前的。
ffmpeg转码离线文件,写的太快?

fmt_in 对应Stream.Feed/File,
 http_send_data时如果不能av_read_frame(c->fmt_in, &pkt),
则设置HTTPSTATE_WAIT_FEED,改变状态通过http_receive_data。

客户端滞后: ?date=

Q: 有没有回绕fmt_in?
A: 
测试: ffmpeg -i 一个足够长的视频 feed1.ffm
ffplay test1.mpg 播大概30秒后停止了。
可以看到ffmpeg 转码速度是明显快于播放速度的。
那个.conf例子VideoFrameRate 3 改成25后,ffplay播了3分钟,有些改善,
但是仍然停了,鼠标点击seek无效。
为什么摄像头的没有停止呢?
在ffmdec.c:93 ffm_read_data 发现读到文件尾时会回绕。
但是ffmenc.c里面没有这样的操作,回绕是在ffserver里面做的。


Q: 如何控制ffmpeg转码速度?
A: ffmpeg -re -i INPUT
"@item -re (@emph{input})
Read input at native frame rate. Mainly used to simulate a grab device."
这个问题折磨我很久了,跟比特率,缓冲区都没有关系。
我不得不发自内心的感叹: "fast forward mpeg, I love you!"


Q:如何保证读指针不会超过写指针呢?
A:由ffm_is_avail_data 和ffm_write_write_index共同保证。
到此我们看到/tmp/mpg.ffm实质上是一个fifo buffer。


ffmpeg -f v4l2 -i /dev/video0  -c:v mpeg1video -f hls - | ffplay - -v 0
虽然可以播,但是ffplay以mpegts播的,就是说m3u8文件完全被忽略掉。


ffmpeg -f v4l2 -i /dev/video0 -c:v mpeg1video -f hls -hls_wrap 5 -hls_list_size 5 http://localhost:8090/hls.ffm


File '/hls0.ts' not found


常规流程是:
http_start_receive_data:
 fd = open(c->stream->feed_filename, O_RDWR); 
 ret = ffm_read_write_index(fd);
 c->buffer_ptr = c->buffer;
 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked")
c->http_error = 0;
c->state = HTTPSTATE_RECEIVE_DATA;
然后是poll,等待信号,http_receive_data。
如果我们也走这样的流程,相当于ts分段基础上再进行ffm分段,显然是不必要的,客户端只
会请求ts分段,并且跟据m3u8管理。


目前的架构:
video0 --> ffmpeg -codec flv1/mpeg4video feed1.ffm <-- flv/rtp --> ffserver <--> ffplay/smplayer 
disk_file/pes --> ffmpeg -codec copy      out.m3u8 --  hls     -->|


用pes而不是原始ts包是因为考虑底层硬件(可能)做了优化处理。还有,考虑到计算能力有限,
尽量不要编解码。


最终部署的架构:
pes_i --> ffmpeg -codec copy feed_i.ffm --flv/hls <--> ffserver <--> players


players
====
包括pcweb端和手机端,功能包括:
显示节目列表,发起连接,断开连接,状态查询/设置.


ffserver
====
http连接管理,url请求/响应/分发.


ffmpeg
====
ffmpeg 模块
输出两路: 
 -->http://localhost:port/feed_0.ffm
 -->hlsenc.c


pes 
====
pes模块输出AVPacket, 传给ffmpeg模块:
ffmpeg -f pes -i /var/pes_0
可参考mpegts.c


if(access(path, F_OK) == -1)mkfifo(path, 0666);
fd = open(path, O_RDWR);




mpegts.c大致流程
====
mpegts_read_header-->pat_cb-->pmt_cb  --> add_pes_stream -->        mpegts_open_pes_filter
mpegts_read_packet-->handle_packets-->handle_packet-->|-->pes_cb=mpegts_push_data


mpegts_read_packet <-- ff_read_packet<-- read_frame_internal <--
av_read_frame<--get_input_packet:ffmpeg.c

is_start = packet[1] & 0x40;
p = packet + 4; //指向pes开始位置
p_end = packet + TS_PACKET_SIZE;
pos = avio_tell(ts->stream->pb);
mpegts_push_data(tss, p, p_end - p, is_start, pos - ts->raw_packet_size)
     PESContext *pes   = filter->u.pes_filter.opaque;
    MpegTSContext *ts = pes->ts;

st = av_mallocz(sizeof(AVStream));
st->index      = s->nb_streams;
s->streams[s->nb_streams++] = st;

todo:
Q:gdb output to stderr.
A: run 1> stdout.txt 2> stderr.txt


Q:tcpdum http content 
A:
 tcpdump -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
 tcpdump -X -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'







你可能感兴趣的:(ffmpeg,Codec)