转载自https://blog.csdn.net/wzw88486969/article/details/78821068
avformat_open_input(http.xxx.m3u8)
init_input(s, filename, &tmp))
//提供的文件名信息不能探测格式
av_probe_input_format2(&pd, 0, &score)))
io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
io_open_default
ffio_open_whitelist
ffurl_alloc
//探测是HTTP协议 URLProtocol ff_http_protocol
url_find_protocol(filename);
ffurl_connect //发送HTTP报文头,下载http.xxx.m3u8文件
//读m3u8文件探测解复用是AVInputFormat *iformat ="hls,applehttp"
*fmt = av_probe_input_buffer2(s->pb, &s->iformat, filename, s, 0, s->format_probesize);
s->iformat->read_header(s); //iformat iformat hls.c-->hls_read_header
s->iformat->read_header(s);
static int hls_read_header(AVFormatContext *s){
//解析m3u8文件,把相应字段放在playlist结构体中,playlist结构体就相当于index.m3u8的数组形式
parse_playlist
ffio_init_context(read_data);
//用read_data读第0片,探测视频文件的解复用是AVInputFormat ff_mpegts_demuxer
av_probe_input_buffer(&pls->pb, &in_fmt, pls->segments[0]->url, NULL, 0, 0);
avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, NULL); //打开第0片视频文件
}
s->iformat->read_packet(s, pkt);
static int hls_read_packet(AVFormatContext *s, AVPacket *pkt){
while(1){
ret = av_read_frame(pls->ctx, &pls->pkt);
if(ret >0){
//没有SEEK的话,读包成功直接退出循环
if (pls->seek_timestamp == AV_NOPTS_VALUE) break;
//有SEEK操作
if (pls->seek_stream_index == pls->pkt.stream_index) {
tb = get_timebase(pls);
ts_diff = av_rescale_rnd(pls->pkt.dts) - pls->seek_timestamp;
//本片中通过比较pkt.dts,seek_timestamp接近了SEEK点,本次SEEK成功
if (ts_diff >= 0 && (pls->pkt.flags & AV_PKT_FLAG_KEY)) {
pls->seek_timestamp = AV_NOPTS_VALUE;
break;
}
}
}
}
}
static int hls_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags){
//根据timestamp在playlist查找是第几片
find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no)
pls->cur_seq_no = seq_no; // read_data会调用current_segment方法,下次下载第seq_no片
pls->seek_stream_index = stream_subdemuxer_index;
ff_format_io_close(pls->parent, &pls->input); //关闭现在正在下载的片input
pls->pb.eof_reached = 0;
/* Clear any buffered data */
pls->pb.buf_end = pls->pb.buf_ptr = pls->pb.buffer;
//hls_read_packet 里面会根据这个seek_timestamp判断下载seq_no片中,第多少帧刚好是这个SEEK点
pls->seek_timestamp = seek_timestamp;
pls->seek_flags = flags;
}
static int hls_close(AVFormatContext *s)
avformat_close_input(&pls->ctx);
static int read_data(void *opaque, uint8_t *buf, int buf_size){ //核心方法
if (!v->input){ //v->input 判断本片是否打开过
seg = current_segment(v);
ret = open_input(c, v, seg);
//http.aaa.x.ts
open_url(v->parent, &v->input, seg->url, c->avio_opts, opts, &is_http)
avio_find_protocol_name(url);
//走HTTP协议,发送HTTP报文头,下载x.ts文件
io_open(s, pb, url, AVIO_FLAG_READ, &tmp)
}
//读HTTP报文体剩下的x.ts文件字节
ret = read_from_url(v, current_segment(v), buf, buf_size, READ_NORMAL);
if (ret > 0){
return ret;
}else{ //本片下载完
ff_format_io_close(v->parent, &v->input); //v->input = NULL
v->cur_seq_no++;
}
}
const URLProtocol ff_http_protocol = {
.name = "http",
.url_open2 = http_open,
.url_accept = http_accept,
.url_handshake = http_handshake,
.url_read = http_read,
.url_write = http_write,
.url_seek = http_seek,
.url_close = http_close,
.url_get_file_handle = http_get_file_handle,
.url_shutdown = http_shutdown,
.priv_data_size = sizeof(HTTPContext),
.priv_data_class = &http_context_class,
.flags = URL_PROTOCOL_FLAG_NETWORK,
.default_whitelist = "http,https,tls,rtp,tcp,udp,crypto,httpproxy"
};
AVInputFormat ff_hls_demuxer = {
.name = "hls,applehttp",
.long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
.priv_class = &hls_class,
.priv_data_size = sizeof(HLSContext),
.read_probe = hls_probe,
.read_header = hls_read_header,
.read_packet = hls_read_packet,
.read_close = hls_close,
.read_seek = hls_read_seek,
};
AVInputFormat ff_mpegts_demuxer = {
.name = "mpegts",
.long_name = NULL_IF_CONFIG_SMALL("MPEG-TS (MPEG-2 Transport Stream)"),
.priv_data_size = sizeof(MpegTSContext),
.read_probe = mpegts_probe,
.read_header = mpegts_read_header,
.read_packet = mpegts_read_packet,
.read_close = mpegts_read_close,
.read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
.priv_class = &mpegts_class,
};
HTTP报文件:
(3671754)request: GET /2017127/5de/529/zehBOsrZo57vbeJy/index.m3u8 HTTP/1.1
User-Agent: Lavf/57.41.100
Accept: */*
Range: bytes=0-
Connection: close
Host: xxxcdn.hls.yyy.tv
Icy-MetaData: 1
[http @ 0x102708000] (3671754)header='HTTP/1.1 206 Partial Content'
[http @ 0x102708000] (3671754)header='Server: Tengine'
[http @ 0x102708000] (3671754)header='Content-Type: application/x-mpegURL'
[http @ 0x102708000] (3671754)header='Content-Length: 36072'
[http @ 0x102708000] (3671754)header='Connection: close'
[http @ 0x102708000] (3671754)header='Date: Thu, 07 Dec 2017 13:20:30 GMT'
[http @ 0x102708000] (3671754)header='x-oss-request-id: 5A29401E5FB1640973AC7221'
[http @ 0x102708000] (3671754)header='Accept-Ranges: bytes'
[http @ 0x102708000] (3671754)header='ETag: "5DBE181ACD4B983E026E19C50BFF23DD"'
[http @ 0x102708000] (3671754)header='Last-Modified: Thu, 07 Dec 2017 13:20:04 GMT'
[http @ 0x102708000] (3671754)header='x-oss-object-type: Normal'
[http @ 0x102708000] (3671754)header='x-oss-hash-crc64ecma: 17784356933318823809'
[http @ 0x102708000] (3671754)header='x-oss-storage-class: Standard'
[http @ 0x102708000] (3671754)header='Content-MD5: Xb4YGs1LmD4CbhnFC/8j3Q=='
[http @ 0x102708000] (3671754)header='x-oss-server-time: 3'
[http @ 0x102708000] (3671754)header='Via: cache25.l2nu20-2[0,200-0,H], cache1.l2nu20-2[0,0], cache8.cn307[0,206-0,H], cache6.cn307[3,0]'
[http @ 0x102708000] (3671754)header='Age: 763084'
[http @ 0x102708000] (3671754)header='X-Cache: HIT TCP_HIT dirn:17:96357170 mlen:-1'
[http @ 0x102708000] (3671754)header='X-Swift-SaveTime: Thu, 07 Dec 2017 15:58:04 GMT'
[http @ 0x102708000] (3671754)header='X-Swift-CacheTime: 2592000'
[http @ 0x102708000] (3671754)header='Content-Range: bytes 0-36071/36072'
[http @ 0x102708000] (3671754)header='access-control-allow-origin: *'
[http @ 0x102708000] (3671754)header='Timing-Allow-Origin: *'
[http @ 0x102708000] (3671754)header='EagleId: 7b81d7ce15134159145938051e'
[http @ 0x102708000] (3671754)header=''
[hls,applehttp @ 0x104007000] Format hls,applehttp probed with size=2048 and score=100
[hls,applehttp @ 0x104007000] Opening 'http://xxxcdn.hls.yyy.tv/2017127/5de/529/zehBOsrZo57vbeJy/0.ts' for reading
[http @ 0x1026275e0]
(3671754)request: GET /2017127/5de/529/zehBOsrZo57vbeJy/0.ts HTTP/1.1
User-Agent: Lavf/57.41.100
Accept: */*
Connection: close
Host: xxxcdn.hls.yyy.tv
Icy-MetaData: 1
[http @ 0x1026275e0] (3671754)header='HTTP/1.1 200 OK'
[http @ 0x1026275e0] (3671754)header='Server: Tengine'
[http @ 0x1026275e0] (3671754)header='Content-Type: video/MP2T'
[http @ 0x1026275e0] (3671754)header='Content-Length: 1233656'
[http @ 0x1026275e0] (3671754)header='Connection: close'
[http @ 0x1026275e0] (3671754)header='Date: Thu, 07 Dec 2017 13:20:31 GMT'
[http @ 0x1026275e0] (3671754)header='x-oss-request-id: 5A29401FF43DB73D87B40E71'
[http @ 0x1026275e0] (3671754)header='Accept-Ranges: bytes'
[http @ 0x1026275e0] (3671754)header='ETag: "8C8A9CAC5FC40404D629A2AF19B84A6F"'
[http @ 0x1026275e0] (3671754)header='Last-Modified: Thu, 07 Dec 2017 10:58:38 GMT'
[http @ 0x1026275e0] (3671754)header='x-oss-object-type: Normal'
[http @ 0x1026275e0] (3671754)header='x-oss-hash-crc64ecma: 13525335145074164730'
[http @ 0x1026275e0] (3671754)header='x-oss-storage-class: Standard'
[http @ 0x1026275e0] (3671754)header='Content-MD5: jIqcrF/EBATWKaKvGbhKbw=='
[http @ 0x1026275e0] (3671754)header='x-oss-server-time: 29'
[http @ 0x1026275e0] (3671754)header='Via: cache42.l2nu20-2[0,200-0,H], cache2.l2nu20-2[0,0], cache2.cn307[0,200-0,H], cache8.cn307[3,0]'
[http @ 0x1026275e0] (3671754)header='Age: 763086'
[http @ 0x1026275e0] (3671754)header='X-Cache: HIT TCP_HIT dirn:15:118266541 mlen:-1'
[http @ 0x1026275e0] (3671754)header='X-Swift-SaveTime: Thu, 07 Dec 2017 13:21:58 GMT'
[http @ 0x1026275e0] (3671754)header='X-Swift-CacheTime: 2592000'
[http @ 0x1026275e0] (3671754)header='access-control-allow-origin: *'
[http @ 0x1026275e0] (3671754)header='Timing-Allow-Origin: *'
[http @ 0x1026275e0] (3671754)header='EagleId: 7b81d7d015134159179953085e'
[http @ 0x1026275e0] (3671754)header=''
..........................................
.......................................... //下载0.ts文件
Format mpegts probed with size=2048 and score=50
(3671754)request: GET /2017127/5de/529/zehBOsrZo57vbeJy/1.ts HTTP/1.1
User-Agent: Lavf/57.41.100
Accept: */*
Connection: close
Host: xxxcdn.hls.yyy.tv
Icy-MetaData: 1
[http @ 0x102509500] (3671754)header='HTTP/1.1 200 OK'
[http @ 0x102509500] (3671754)header='Server: Tengine'
[http @ 0x102509500] (3671754)header='Content-Type: video/MP2T'
[http @ 0x102509500] (3671754)header='Content-Length: 1162028'
[http @ 0x102509500] (3671754)header='Connection: close'
[http @ 0x102509500] (3671754)header='Date: Thu, 07 Dec 2017 13:20:31 GMT'
[http @ 0x102509500] (3671754)header='x-oss-request-id: 5A29401F83B4CE0AA7B40025'
[http @ 0x102509500] (3671754)header='Accept-Ranges: bytes'
[http @ 0x102509500] (3671754)header='ETag: "95EFDEADB86482C551F1BCF868ECEA41"'
[http @ 0x102509500] (3671754)header='Last-Modified: Thu, 07 Dec 2017 10:58:49 GMT'
[http @ 0x102509500] (3671754)header='x-oss-object-type: Normal'
[http @ 0x102509500] (3671754)header='x-oss-hash-crc64ecma: 5079365695105828960'
[http @ 0x102509500] (3671754)header='x-oss-storage-class: Standard'
[http @ 0x102509500] (3671754)header='Content-MD5: le/erbhkgsVR8bz4aOzqQQ=='
[http @ 0x102509500] (3671754)header='x-oss-server-time: 33'
[http @ 0x102509500] (3671754)header='Via: cache31.l2nu20-2[0,200-0,H], cache10.l2nu20-2[2,0], cache7.cn307[0,200-0,H], cache3.cn307[28,0]'
[http @ 0x102509500] (3671754)header='Age: 763096'
[http @ 0x102509500] (3671754)header='X-Cache: HIT TCP_HIT dirn:5:256912714 mlen:-1'
[http @ 0x102509500] (3671754)header='X-Swift-SaveTime: Thu, 07 Dec 2017 15:58:06 GMT'
[http @ 0x102509500] (3671754)header='X-Swift-CacheTime: 2592000'
[http @ 0x102509500] (3671754)header='access-control-allow-origin: *'
[http @ 0x102509500] (3671754)header='Timing-Allow-Origin: *'
[http @ 0x102509500] (3671754)header='EagleId: 7b81d7cb15134159275121813e'
[http @ 0x102509500] (3671754)header=''
..........................................
.......................................... //下载1.ts文件