• FFMpeg笔记(七) 代码结构分析,以HLS为例


    HLS流在播放时是先解协议(hls.c)后解封装(mpegts.c),libavformat下的hls.c和mpegts.c实际上是同一个级别的,同属于demuxer。

    一、解HLS协议

    1. FFmpeg代码分析    

        首先看一下ff_hls_demuxer的定义:

    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,
    };

    (1)FFmpeg在拿到hls流后,它一开始并不知道该用哪个demuxer,这个时候它会进行probe,即依次调用demuxer的read_probe函数,选择返回分数最高的一个demuxer,最后选定ff_hls_demuxer。AVFormatContext中的s->iformat->priv_data一般是指demuxer内部的结构体,在解HLS协议时,这个priv_data就是HLSContext;

    (2)之后FFmpeg会调用read_header函数,即执行hls_read_header,获取hls的播放列表,并赋值到HLSContext结构体中;

    (3)当准备工作妥当后,FFmpeg会调用hls_read_packet读取数据,传递给上层;

    (4)如果有seek操作会执行hls_read_seek;

    (5)视频关闭时,FFmpeg会调用hls_close;

    2. discontinue字段

        FFmpeg3.4没有支持HLS标准的discontinue字段。discontinue字段常用于ts播放列表里插入一段广告,这段广告的参数可以与正片的参数不一致。上层在识别到这个参数后,可以重置解码器。对于iOS,需要重新创建解码器,对于Android,解码器兼容了这种情况,无需重新创建解码器。

    二、解ts封装 

    以mpegts.c为例,probe一般是将读取到的probe数据与ts格式对比,如果是ts格式则返回高分数,上层选择最高的分数的demuxer;

    PES包:分割打包的ES流,加入了PES头。

    struct MpegTSFilter {
        int pid;
        int es_id;
        int last_cc; /* last cc code (-1 if first packet) */
        int64_t last_pcr;
        enum MpegTSFilterType type;
        union {// 一个Filter是下边的一种类型
            MpegTSPESFilter pes_filter;
            MpegTSSectionFilter section_filter;
        } u;
    };

    handle_packet函数处理一个ts包,在函数中switch case语句中处理ts包。一般是先处理ts header, 之后是pes header,代码中状态定义:

    /* TS stream handling */
    // 标识TS流状态
    enum MpegTSState {
        MPEGTS_HEADER = 0,
        MPEGTS_PESHEADER,
        MPEGTS_PESHEADER_FILL,
        MPEGTS_PAYLOAD,
        MPEGTS_SKIP,
    };

     从av_read_frame读到的pkt,其音频和视频的pts是连续的,但是两者之间不是连续的,因为pts乘以时基才是真正的显示时间,比如如下打印日志,pkt时间进行换算后,可以看到其整体pts是连续的。

    martinjia time_base:1 30000, pkt index:0, pkt pts:83083(pts换算后:2.76s)
    martinjia martinjia time_base:1 48000, pkt index:1, pkt pts:118784(pts换算后:2.47s)

  • 相关阅读:
    common-fileupload上传图片并显示图片
    common-fileupload上传文件
    Hibernate映射文件配置(hbm.xml和注解方式)
    hdu1272:小希的迷宫(并查集)
    hdu1272:小希的迷宫(并查集)
    hdu1102:Constructing Roads(最小生成树)
    hdu1102:Constructing Roads(最小生成树)
    hdu1054:Strategic Game(最小点覆盖)
    hdu1054:Strategic Game(最小点覆盖)
    hdu2255:奔小康赚大钱(KM)
  • 原文地址:https://www.cnblogs.com/jiayayao/p/9381744.html
Copyright © 2020-2023  润新知