ffmpeg hls.c分析

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文件


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值